Merge remote-tracking branch 'origin/1.20' into 1.21.1
This commit is contained in:
commit
60d3026ea6
|
|
@ -1,108 +0,0 @@
|
||||||
package org.embeddedt.modernfix.resources;
|
|
||||||
|
|
||||||
import com.google.common.base.Splitter;
|
|
||||||
import com.google.common.collect.Interner;
|
|
||||||
import com.google.common.collect.Interners;
|
|
||||||
import org.embeddedt.modernfix.util.FileUtil;
|
|
||||||
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
public class CachedResourcePath {
|
|
||||||
private final String[] pathComponents;
|
|
||||||
|
|
||||||
public static final Interner<String> PATH_COMPONENT_INTERNER = Interners.newStrongInterner();
|
|
||||||
private static final Splitter SLASH_SPLITTER = Splitter.on('/');
|
|
||||||
public static final String[] NO_PREFIX = new String[0];
|
|
||||||
|
|
||||||
public CachedResourcePath(String[] prefix, Path path) {
|
|
||||||
this(prefix, path, path.getNameCount(), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CachedResourcePath(String s) {
|
|
||||||
// normalize so we can guarantee there are no empty sections
|
|
||||||
this(NO_PREFIX, SLASH_SPLITTER.splitToList(FileUtil.normalize(s)), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T> CachedResourcePath(String[] prefixElements, Collection<T> collection, boolean intern) {
|
|
||||||
this(prefixElements, collection, collection.size(), intern);
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T> CachedResourcePath(String[] prefixElements, Iterable<T> path, int count, boolean intern) {
|
|
||||||
String[] components = new String[prefixElements.length + count];
|
|
||||||
int i = 0;
|
|
||||||
while(i < prefixElements.length) {
|
|
||||||
components[i] = intern ? PATH_COMPONENT_INTERNER.intern(prefixElements[i]) : prefixElements[i];
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
for(Object component : path) {
|
|
||||||
String s = component.toString();
|
|
||||||
if(s.length() == 0)
|
|
||||||
continue;
|
|
||||||
components[i] = intern ? PATH_COMPONENT_INTERNER.intern(s) : s;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
pathComponents = components;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CachedResourcePath(String[] prefixElements, CachedResourcePath other) {
|
|
||||||
String[] components = new String[prefixElements.length + other.pathComponents.length];
|
|
||||||
int i = 0;
|
|
||||||
while(i < prefixElements.length) {
|
|
||||||
components[i] = PATH_COMPONENT_INTERNER.intern(prefixElements[i]);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
System.arraycopy(other.pathComponents, 0, components, i, other.pathComponents.length);
|
|
||||||
pathComponents = components;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DOES NOT INTERN!
|
|
||||||
*/
|
|
||||||
public CachedResourcePath(String[] pathComponents) {
|
|
||||||
for(String s : pathComponents) {
|
|
||||||
if(s.length() == 0) {
|
|
||||||
// reconstruct the whole array skipping blanks. inefficient, but should not be the common case
|
|
||||||
pathComponents = Arrays.stream(pathComponents).filter(comp -> comp.length() > 0).toArray(String[]::new);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.pathComponents = pathComponents;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Arrays.hashCode(pathComponents);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (this == o) return true;
|
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
|
||||||
CachedResourcePath that = (CachedResourcePath) o;
|
|
||||||
return Arrays.equals(pathComponents, that.pathComponents);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getFileName() {
|
|
||||||
return pathComponents[pathComponents.length - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getNameCount() {
|
|
||||||
return pathComponents.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getNameAt(int i) {
|
|
||||||
return pathComponents[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getFullPath(int startIndex) {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
for(int i = startIndex; i < pathComponents.length; i++) {
|
|
||||||
sb.append(pathComponents[i]);
|
|
||||||
if(i != (pathComponents.length - 1))
|
|
||||||
sb.append('/');
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
package org.embeddedt.modernfix.resources;
|
|
||||||
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.server.packs.PackResources;
|
|
||||||
import net.minecraft.server.packs.resources.IoSupplier;
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
public class NewResourcePackAdapter {
|
|
||||||
public static void sendToOutput(Function<ResourceLocation, IoSupplier<InputStream>> streamCreator, PackResources.ResourceOutput output, Collection<ResourceLocation> locations) {
|
|
||||||
for(ResourceLocation rl : locations) {
|
|
||||||
output.accept(rl, streamCreator.apply(rl));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
package org.embeddedt.modernfix.neoforge.dynresources;
|
package org.embeddedt.modernfix.neoforge.dynresources;
|
||||||
|
|
||||||
import com.google.common.collect.ForwardingMap;
|
import com.google.common.collect.ForwardingMap;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.collect.Iterators;
|
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import com.google.common.graph.GraphBuilder;
|
import com.google.common.graph.GraphBuilder;
|
||||||
import com.google.common.graph.MutableGraph;
|
import com.google.common.graph.MutableGraph;
|
||||||
|
|
@ -12,7 +11,6 @@ import net.minecraft.client.resources.model.BakedModel;
|
||||||
import net.minecraft.client.resources.model.ModelBakery;
|
import net.minecraft.client.resources.model.ModelBakery;
|
||||||
import net.minecraft.client.resources.model.ModelResourceLocation;
|
import net.minecraft.client.resources.model.ModelResourceLocation;
|
||||||
import net.minecraft.core.registries.BuiltInRegistries;
|
import net.minecraft.core.registries.BuiltInRegistries;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.neoforged.fml.ModContainer;
|
import net.neoforged.fml.ModContainer;
|
||||||
import net.neoforged.fml.ModList;
|
import net.neoforged.fml.ModList;
|
||||||
|
|
@ -21,7 +19,17 @@ import org.embeddedt.modernfix.ModernFix;
|
||||||
import org.embeddedt.modernfix.util.ForwardingInclDefaultsMap;
|
import org.embeddedt.modernfix.util.ForwardingInclDefaultsMap;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.AbstractSet;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -29,22 +37,27 @@ import java.util.function.BiFunction;
|
||||||
* of the model registry that emulates vanilla keySet behavior.
|
* of the model registry that emulates vanilla keySet behavior.
|
||||||
*/
|
*/
|
||||||
public class ModelBakeEventHelper {
|
public class ModelBakeEventHelper {
|
||||||
// TODO: make into config option
|
|
||||||
private static final Set<String> INCOMPATIBLE_MODS = ImmutableSet.of(
|
private enum UniverseVisibility {
|
||||||
"industrialforegoing",
|
/**
|
||||||
"mekanism",
|
* Mod cannot see any view of the universe of model locations.
|
||||||
"vampirism",
|
*/
|
||||||
"elevatorid",
|
NONE,
|
||||||
"cfm",
|
/**
|
||||||
"refinedstorage",
|
* Mod can see its own model locations and those of dependencies/dependents.
|
||||||
"embers",
|
*/
|
||||||
"buildcraftsilicon",
|
SELF_AND_DEPS,
|
||||||
"buildcrafttransport",
|
/**
|
||||||
"buildcraftfactory");
|
* Mod can see every model location.
|
||||||
|
*/
|
||||||
|
EVERYTHING
|
||||||
|
}
|
||||||
|
private static final Map<String, UniverseVisibility> MOD_VISIBILITY_CONFIGURATION = ImmutableMap.<String, UniverseVisibility>builder()
|
||||||
|
.build();
|
||||||
private final Map<ModelResourceLocation, BakedModel> modelRegistry;
|
private final Map<ModelResourceLocation, BakedModel> modelRegistry;
|
||||||
private final Set<ModelResourceLocation> topLevelModelLocations;
|
private final Set<ModelResourceLocation> topLevelModelLocations;
|
||||||
|
|
||||||
private final MutableGraph<String> dependencyGraph;
|
private final MutableGraph<String> dependencyGraph;
|
||||||
|
|
||||||
public ModelBakeEventHelper(Map<ModelResourceLocation, BakedModel> modelRegistry) {
|
public ModelBakeEventHelper(Map<ModelResourceLocation, BakedModel> modelRegistry) {
|
||||||
this.modelRegistry = modelRegistry;
|
this.modelRegistry = modelRegistry;
|
||||||
this.topLevelModelLocations = new ObjectLinkedOpenHashSet<>();
|
this.topLevelModelLocations = new ObjectLinkedOpenHashSet<>();
|
||||||
|
|
@ -55,25 +68,30 @@ public class ModelBakeEventHelper {
|
||||||
topLevelModelLocations.add(BlockModelShaper.stateToModelLocation(location, state));
|
topLevelModelLocations.add(BlockModelShaper.stateToModelLocation(location, state));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
BuiltInRegistries.ITEM.keySet().forEach(location -> topLevelModelLocations.add(new ModelResourceLocation(location, "inventory")));
|
BuiltInRegistries.ITEM.keySet().forEach(key -> topLevelModelLocations.add(new ModelResourceLocation(key, "inventory")));
|
||||||
this.topLevelModelLocations.addAll(modelRegistry.keySet());
|
this.topLevelModelLocations.addAll(modelRegistry.keySet());
|
||||||
this.dependencyGraph = GraphBuilder.undirected().build();
|
this.dependencyGraph = buildDependencyGraph();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MutableGraph<String> buildDependencyGraph() {
|
||||||
|
MutableGraph<String> dependencyGraph = GraphBuilder.undirected().build();
|
||||||
ModList.get().forEachModContainer((id, mc) -> {
|
ModList.get().forEachModContainer((id, mc) -> {
|
||||||
this.dependencyGraph.addNode(id);
|
dependencyGraph.addNode(id);
|
||||||
for(IModInfo.ModVersion version : mc.getModInfo().getDependencies()) {
|
for(IModInfo.ModVersion version : mc.getModInfo().getDependencies()) {
|
||||||
this.dependencyGraph.addNode(version.getModId());
|
dependencyGraph.addNode(version.getModId());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
for(String id : this.dependencyGraph.nodes()) {
|
for(String id : dependencyGraph.nodes()) {
|
||||||
Optional<? extends ModContainer> mContainer = ModList.get().getModContainerById(id);
|
Optional<? extends ModContainer> mContainer = ModList.get().getModContainerById(id);
|
||||||
if(mContainer.isPresent()) {
|
if(mContainer.isPresent()) {
|
||||||
for(IModInfo.ModVersion version : mContainer.get().getModInfo().getDependencies()) {
|
for(IModInfo.ModVersion version : mContainer.get().getModInfo().getDependencies()) {
|
||||||
// avoid self-loops
|
// avoid self-loops
|
||||||
if(!Objects.equals(id, version.getModId()))
|
if(!Objects.equals(id, version.getModId()))
|
||||||
this.dependencyGraph.putEdge(id, version.getModId());
|
dependencyGraph.putEdge(id, version.getModId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return dependencyGraph;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Set<String> WARNED_MOD_IDS = new HashSet<>();
|
private static final Set<String> WARNED_MOD_IDS = new HashSet<>();
|
||||||
|
|
@ -124,73 +142,94 @@ public class ModelBakeEventHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<ModelResourceLocation, BakedModel> wrapRegistry(String modId) {
|
public Map<ModelResourceLocation, BakedModel> wrapRegistry(String modId) {
|
||||||
|
var config = MOD_VISIBILITY_CONFIGURATION.getOrDefault(modId, UniverseVisibility.EVERYTHING);
|
||||||
|
if (config == UniverseVisibility.NONE) {
|
||||||
|
return createWarningRegistry(modId);
|
||||||
|
}
|
||||||
final Set<String> modIdsToInclude = new HashSet<>();
|
final Set<String> modIdsToInclude = new HashSet<>();
|
||||||
modIdsToInclude.add(modId);
|
modIdsToInclude.add(modId);
|
||||||
try {
|
try {
|
||||||
modIdsToInclude.addAll(this.dependencyGraph.adjacentNodes(modId));
|
modIdsToInclude.addAll(this.dependencyGraph.adjacentNodes(modId));
|
||||||
} catch(IllegalArgumentException ignored) { /* sanity check */ }
|
} catch(IllegalArgumentException ignored) { /* sanity check */ }
|
||||||
modIdsToInclude.remove("minecraft");
|
modIdsToInclude.remove("minecraft");
|
||||||
if(modIdsToInclude.stream().noneMatch(INCOMPATIBLE_MODS::contains))
|
Set<ModelResourceLocation> ourModelLocations;
|
||||||
return createWarningRegistry(modId);
|
if (config == UniverseVisibility.SELF_AND_DEPS) {
|
||||||
Set<ModelResourceLocation> ourModelLocations = Sets.filter(this.topLevelModelLocations, loc -> modIdsToInclude.contains(loc.id().getNamespace()));
|
ourModelLocations = Sets.filter(this.topLevelModelLocations, loc -> modIdsToInclude.contains(loc.id().getNamespace()));
|
||||||
BakedModel missingModel = modelRegistry.get(ModelBakery.MISSING_MODEL_VARIANT);
|
} else {
|
||||||
return new ForwardingMap<ModelResourceLocation, BakedModel>() {
|
ourModelLocations = this.topLevelModelLocations;
|
||||||
@Override
|
}
|
||||||
protected Map<ModelResourceLocation, BakedModel> delegate() {
|
BakedModel missingModel = modelRegistry.get(ModelBakery.MISSING_MODEL_LOCATION);
|
||||||
return modelRegistry;
|
return new EmulatedModelRegistry(modId, modIdsToInclude, missingModel, ourModelLocations);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public class EmulatedModelRegistry extends ForwardingMap<ModelResourceLocation, BakedModel> {
|
||||||
public BakedModel get(@Nullable Object key) {
|
private final Set<String> modIdsToInclude;
|
||||||
BakedModel model = super.get(key);
|
private final BakedModel missingModel;
|
||||||
if(model == null && key != null && modIdsToInclude.contains(((ResourceLocation)key).getNamespace())) {
|
private final Set<ModelResourceLocation> ourModelLocations;
|
||||||
ModernFix.LOGGER.warn("Model {} is missing, but was requested in model bake event. Returning missing model", key);
|
private final String modId;
|
||||||
return missingModel;
|
|
||||||
|
private EmulatedModelRegistry(String modId, Set<String> modIdsToInclude, BakedModel missingModel, Set<ModelResourceLocation> ourModelLocations) {
|
||||||
|
this.modId = modId;
|
||||||
|
this.modIdsToInclude = modIdsToInclude;
|
||||||
|
this.missingModel = missingModel;
|
||||||
|
this.ourModelLocations = ourModelLocations;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Map<ModelResourceLocation, BakedModel> delegate() {
|
||||||
|
return modelRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BakedModel get(@Nullable Object key) {
|
||||||
|
BakedModel model = super.get(key);
|
||||||
|
if(model == null && key instanceof ModelResourceLocation mrl && modIdsToInclude.contains(mrl.id().getNamespace())) {
|
||||||
|
ModernFix.LOGGER.warn("Model {} is missing, but was requested in model bake event. Returning missing model", key);
|
||||||
|
return missingModel;
|
||||||
|
}
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<ModelResourceLocation> keySet() {
|
||||||
|
return Collections.unmodifiableSet(ourModelLocations);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean containsKey(@Nullable Object key) {
|
||||||
|
return ourModelLocations.contains(key) || super.containsKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<Entry<ModelResourceLocation, BakedModel>> entrySet() {
|
||||||
|
return new DynamicModelEntrySet(this, ourModelLocations);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void replaceAll(BiFunction<? super ModelResourceLocation, ? super BakedModel, ? extends BakedModel> function) {
|
||||||
|
ModernFix.LOGGER.warn("Mod '{}' is calling replaceAll on the model registry. Some hacks will be used to keep this fast, but they may not be 100% compatible.", modId);
|
||||||
|
List<ModelResourceLocation> locations = new ArrayList<>(ourModelLocations);
|
||||||
|
for(ModelResourceLocation location : locations) {
|
||||||
|
/*
|
||||||
|
* Fetching every model is insanely slow. So we call the function with a null object first, since it
|
||||||
|
* probably isn't expecting that. If we get an exception thrown, or it returns nonnull, then we know
|
||||||
|
* it actually cares about the given model.
|
||||||
|
*/
|
||||||
|
boolean needsReplacement;
|
||||||
|
try {
|
||||||
|
needsReplacement = function.apply(location, null) != null;
|
||||||
|
} catch(Throwable e) {
|
||||||
|
needsReplacement = true;
|
||||||
}
|
}
|
||||||
return model;
|
if(needsReplacement) {
|
||||||
}
|
BakedModel existing = get(location);
|
||||||
|
BakedModel replacement = function.apply(location, existing);
|
||||||
@Override
|
if(replacement != existing) {
|
||||||
public Set<ModelResourceLocation> keySet() {
|
put(location, replacement);
|
||||||
return ourModelLocations;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean containsKey(@Nullable Object key) {
|
|
||||||
return ourModelLocations.contains(key) || super.containsKey(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<Entry<ModelResourceLocation, BakedModel>> entrySet() {
|
|
||||||
return new DynamicModelEntrySet(this, ourModelLocations);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void replaceAll(BiFunction<? super ModelResourceLocation, ? super BakedModel, ? extends BakedModel> function) {
|
|
||||||
ModernFix.LOGGER.warn("Mod '{}' is calling replaceAll on the model registry. Some hacks will be used to keep this fast, but they may not be 100% compatible.", modId);
|
|
||||||
List<ModelResourceLocation> locations = new ArrayList<>(keySet());
|
|
||||||
for(ModelResourceLocation location : locations) {
|
|
||||||
/*
|
|
||||||
* Fetching every model is insanely slow. So we call the function with a null object first, since it
|
|
||||||
* probably isn't expecting that. If we get an exception thrown, or it returns nonnull, then we know
|
|
||||||
* it actually cares about the given model.
|
|
||||||
*/
|
|
||||||
boolean needsReplacement;
|
|
||||||
try {
|
|
||||||
needsReplacement = function.apply(location, null) != null;
|
|
||||||
} catch(Throwable e) {
|
|
||||||
needsReplacement = true;
|
|
||||||
}
|
|
||||||
if(needsReplacement) {
|
|
||||||
BakedModel existing = get(location);
|
|
||||||
BakedModel replacement = function.apply(location, existing);
|
|
||||||
if(replacement != existing) {
|
|
||||||
put(location, replacement);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class DynamicModelEntrySet extends AbstractSet<Map.Entry<ModelResourceLocation, BakedModel>> {
|
private static class DynamicModelEntrySet extends AbstractSet<Map.Entry<ModelResourceLocation, BakedModel>> {
|
||||||
|
|
@ -204,7 +243,18 @@ public class ModelBakeEventHelper {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Iterator<Map.Entry<ModelResourceLocation, BakedModel>> iterator() {
|
public Iterator<Map.Entry<ModelResourceLocation, BakedModel>> iterator() {
|
||||||
return Iterators.transform(Iterators.unmodifiableIterator(this.modelLocations.iterator()), DynamicModelEntry::new);
|
var iter = this.modelLocations.iterator();
|
||||||
|
return new Iterator<>() {
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return iter.hasNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map.Entry<ModelResourceLocation, BakedModel> next() {
|
||||||
|
return new DynamicModelEntry(iter.next());
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package org.embeddedt.modernfix.neoforge.mixin.perf.dynamic_resources;
|
package org.embeddedt.modernfix.neoforge.mixin.perf.dynamic_resources;
|
||||||
|
|
||||||
import com.google.common.base.Stopwatch;
|
import com.google.common.base.Stopwatch;
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||||
import net.minecraft.client.resources.model.BakedModel;
|
import net.minecraft.client.resources.model.BakedModel;
|
||||||
import net.minecraft.client.resources.model.ModelResourceLocation;
|
import net.minecraft.client.resources.model.ModelResourceLocation;
|
||||||
import net.neoforged.bus.api.Event;
|
import net.neoforged.bus.api.Event;
|
||||||
|
|
@ -17,6 +18,8 @@ import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
|
@ -32,19 +35,28 @@ public class ForgeHooksClientMixin {
|
||||||
ModelEvent.ModifyBakingResult bakeEvent = ((ModelEvent.ModifyBakingResult)event);
|
ModelEvent.ModifyBakingResult bakeEvent = ((ModelEvent.ModifyBakingResult)event);
|
||||||
ModelBakeEventHelper helper = new ModelBakeEventHelper(bakeEvent.getModels());
|
ModelBakeEventHelper helper = new ModelBakeEventHelper(bakeEvent.getModels());
|
||||||
Method acceptEv = ObfuscationReflectionHelper.findMethod(ModContainer.class, "acceptEvent", Event.class);
|
Method acceptEv = ObfuscationReflectionHelper.findMethod(ModContainer.class, "acceptEvent", Event.class);
|
||||||
|
Stopwatch globalTimer = Stopwatch.createStarted();
|
||||||
|
Map<String, Stopwatch> times = new Object2ObjectOpenHashMap<>();
|
||||||
ModList.get().forEachModContainer((id, mc) -> {
|
ModList.get().forEachModContainer((id, mc) -> {
|
||||||
Map<ModelResourceLocation, BakedModel> newRegistry = helper.wrapRegistry(id);
|
Map<ModelResourceLocation, BakedModel> newRegistry = helper.wrapRegistry(id);
|
||||||
ModelEvent.ModifyBakingResult postedEvent = new ModelEvent.ModifyBakingResult(newRegistry, bakeEvent.getTextureGetter(), bakeEvent.getModelBakery());
|
ModelEvent.ModifyBakingResult postedEvent = new ModelEvent.ModifyBakingResult(newRegistry, bakeEvent.getTextureGetter(), bakeEvent.getModelBakery());
|
||||||
Stopwatch timer = Stopwatch.createStarted();
|
Stopwatch timer = times.computeIfAbsent(id, $ -> Stopwatch.createStarted());
|
||||||
try {
|
try {
|
||||||
acceptEv.invoke(mc, postedEvent);
|
acceptEv.invoke(mc, postedEvent);
|
||||||
} catch(ReflectiveOperationException e) {
|
} catch(ReflectiveOperationException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
timer.stop();
|
timer.stop();
|
||||||
if(timer.elapsed(TimeUnit.SECONDS) >= 1) {
|
|
||||||
ModernFix.LOGGER.warn("Mod '{}' took {} in the model bake event", id, timer);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
globalTimer.stop();
|
||||||
|
if (globalTimer.elapsed(TimeUnit.SECONDS) >= 1) {
|
||||||
|
ModernFix.LOGGER.warn("Posting dynamic ModelEvent.ModifyBakingResult to mods took {}, breakdown below:", globalTimer);
|
||||||
|
times.entrySet().stream()
|
||||||
|
.sorted(Comparator.<Map.Entry<String, Stopwatch>, Duration>comparing(e -> e.getValue().elapsed()).reversed())
|
||||||
|
.filter(e -> e.getValue().elapsed(TimeUnit.MILLISECONDS) > 50)
|
||||||
|
.forEach(entry -> {
|
||||||
|
ModernFix.LOGGER.warn(" {}: {}", entry.getKey(), entry.getValue().toString());
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user