From a13587e1397e5c714164ad798a3bacc1671d1dbf Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 18 May 2025 21:55:51 -0400 Subject: [PATCH] Fix presizing of model location set & use more efficient string generation logic --- .../dynresources/ModelBakeEventHelper.java | 15 +++-- .../dynresources/ModelLocationBuilder.java | 61 +++++++++++++++++++ 2 files changed, 68 insertions(+), 8 deletions(-) create mode 100644 forge/src/main/java/org/embeddedt/modernfix/forge/dynresources/ModelLocationBuilder.java diff --git a/forge/src/main/java/org/embeddedt/modernfix/forge/dynresources/ModelBakeEventHelper.java b/forge/src/main/java/org/embeddedt/modernfix/forge/dynresources/ModelBakeEventHelper.java index b520de86..6aa2d06e 100644 --- a/forge/src/main/java/org/embeddedt/modernfix/forge/dynresources/ModelBakeEventHelper.java +++ b/forge/src/main/java/org/embeddedt/modernfix/forge/dynresources/ModelBakeEventHelper.java @@ -6,14 +6,11 @@ import com.google.common.collect.Sets; import com.google.common.graph.GraphBuilder; import com.google.common.graph.MutableGraph; import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet; -import net.minecraft.client.renderer.block.BlockModelShaper; import net.minecraft.client.resources.model.BakedModel; import net.minecraft.client.resources.model.ModelBakery; import net.minecraft.client.resources.model.ModelResourceLocation; 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.minecraftforge.fml.ModContainer; import net.minecraftforge.fml.ModList; import net.minecraftforge.forgespi.language.IModInfo; @@ -60,13 +57,15 @@ public class ModelBakeEventHelper { private final MutableGraph dependencyGraph; public ModelBakeEventHelper(Map modelRegistry) { this.modelRegistry = modelRegistry; - this.topLevelModelLocations = new ObjectLinkedOpenHashSet<>(Block.BLOCK_STATE_REGISTRY.size() + BuiltInRegistries.ITEM.size()); - // Skip going through ModelLocationCache because most of the accesses will be misses + int blockStateCount = 0; + for (var b : BuiltInRegistries.BLOCK) { + blockStateCount += b.getStateDefinition().getPossibleStates().size(); + } + this.topLevelModelLocations = new ObjectLinkedOpenHashSet<>(blockStateCount + BuiltInRegistries.ITEM.size()); + var modelLocationBuilder = new ModelLocationBuilder(); BuiltInRegistries.BLOCK.entrySet().forEach(entry -> { var location = entry.getKey().location(); - for(BlockState state : entry.getValue().getStateDefinition().getPossibleStates()) { - topLevelModelLocations.add(BlockModelShaper.stateToModelLocation(location, state)); - } + modelLocationBuilder.generateForBlock(topLevelModelLocations, entry.getValue(), location); }); BuiltInRegistries.ITEM.keySet().forEach(key -> topLevelModelLocations.add(new ModelResourceLocation(key, "inventory"))); this.topLevelModelLocations.addAll(modelRegistry.keySet()); diff --git a/forge/src/main/java/org/embeddedt/modernfix/forge/dynresources/ModelLocationBuilder.java b/forge/src/main/java/org/embeddedt/modernfix/forge/dynresources/ModelLocationBuilder.java new file mode 100644 index 00000000..69ca564d --- /dev/null +++ b/forge/src/main/java/org/embeddedt/modernfix/forge/dynresources/ModelLocationBuilder.java @@ -0,0 +1,61 @@ +package org.embeddedt.modernfix.forge.dynresources; + +import com.google.common.collect.Lists; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import net.minecraft.client.resources.model.ModelResourceLocation; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.properties.Property; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +public class ModelLocationBuilder { + private final Object2ObjectOpenHashMap, PropertyData> propertyToOptionStrings = new Object2ObjectOpenHashMap<>(); + private final StringBuilder builder = new StringBuilder(); + + private record PropertyData(List nameValuePairs, int maxPairLength) {} + + public void generateForBlock(Set destinationSet, Block block, ResourceLocation baseLocation) { + var props = block.getStateDefinition().getProperties(); + List> optionsList = new ArrayList<>(); + int requiredBuilderSize = Math.max(0, props.size() - 1); // commas + for (var prop : props) { + var data = propertyToOptionStrings.computeIfAbsent(prop, ModelLocationBuilder::computePropertyOptions); + optionsList.add(data.nameValuePairs); + requiredBuilderSize += data.maxPairLength; + } + var product = Lists.cartesianProduct(optionsList); + int count = product.size(); + int tupleEntryCount = optionsList.size(); + StringBuilder stringbuilder = this.builder; + stringbuilder.ensureCapacity(requiredBuilderSize); + for (int i = 0; i < count; i++) { + stringbuilder.setLength(0); + var result = product.get(i); + for (int j = 0; j < tupleEntryCount; j++) { + if (j != 0) { + stringbuilder.append(','); + } + stringbuilder.append(result.get(j)); + } + destinationSet.add(new ModelResourceLocation(baseLocation, stringbuilder.toString())); + } + } + + private static PropertyData computePropertyOptions(Property prop) { + List valuesList = new ArrayList<>(prop.getPossibleValues().size()); + int maxLength = 0; + for (var val : prop.getPossibleValues()) { + String pair = prop.getName() + "=" + getValueName(prop, val); + valuesList.add(pair); + maxLength = Math.max(pair.length(), maxLength); + } + return new PropertyData(List.copyOf(valuesList), maxLength); + } + + private static > String getValueName(Property property, Comparable value) { + return property.getName((T)value); + } +}