diff --git a/build.gradle b/build.gradle index a3abaf78..ac48b77d 100644 --- a/build.gradle +++ b/build.gradle @@ -18,7 +18,7 @@ plugins { apply plugin: 'org.spongepowered.mixin' group = 'org.embeddedt' -version = '1.6.0-beta1' +version = '1.6.0-beta2' java { archivesBaseName = 'modernfix-mc' + minecraft_version diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/faster_baking/ModelBakeryMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/faster_baking/ModelBakeryMixin.java index addf1256..df5dabf2 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/faster_baking/ModelBakeryMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/faster_baking/ModelBakeryMixin.java @@ -8,18 +8,19 @@ import net.minecraft.client.renderer.texture.SpriteMap; import net.minecraft.client.renderer.texture.TextureManager; import net.minecraft.profiler.IProfiler; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.vector.TransformationMatrix; import net.minecraftforge.fml.loading.progress.StartupMessageManager; +import org.apache.commons.lang3.tuple.Triple; import org.apache.logging.log4j.Logger; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.*; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import javax.annotation.Nullable; import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; @Mixin(ModelBakery.class) @@ -37,10 +38,19 @@ public abstract class ModelBakeryMixin { @Shadow @Nullable private SpriteMap atlasSet; @Shadow @Final private Map unbakedCache; + @Shadow @Mutable + @Final private Map, IBakedModel> bakedCache; private Map> modelsToBakeParallel; private boolean canBakeParallel(IUnbakedModel unbakedModel) { - return false; + if(!(unbakedModel instanceof BlockModel)) + return false; + else { + BlockModel model = (BlockModel)unbakedModel; + if(model.customData.hasCustomGeometry()) + return false; + return true; + } } @Inject(method = "processLoading", at = @At(value = "INVOKE", target = "Lnet/minecraft/profiler/IProfiler;pop()V")) @@ -56,18 +66,17 @@ public abstract class ModelBakeryMixin { pProfiler.popPush("baking"); StartupMessageManager.mcLoaderConsumer().ifPresent(c -> c.accept("Baking models")); this.atlasSet = new SpriteMap(this.atlasPreparations.values().stream().map(Pair::getFirst).collect(Collectors.toList())); + this.bakedCache = new ConcurrentHashMap<>(); this.modelsToBakeParallel = this.topLevelModels.keySet().stream() .collect(Collectors.partitioningBy(location -> { - return true; - /* IUnbakedModel unbakedModel = this.unbakedCache.get(location); if(unbakedModel == null) return false; else return this.canBakeParallel(unbakedModel); - */ })); List parallelModels = this.modelsToBakeParallel.get(true); + List> futures = new ArrayList<>(); parallelModels.forEach((p_229350_1_) -> { IBakedModel ibakedmodel = null; diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/BooleanPropertyMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/BooleanPropertyMixin.java new file mode 100644 index 00000000..7474c762 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/BooleanPropertyMixin.java @@ -0,0 +1,19 @@ +package org.embeddedt.modernfix.mixin.perf.parallelize_model_loading; + +import com.google.common.collect.ImmutableSet; +import net.minecraft.state.BooleanProperty; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(BooleanProperty.class) +public class BooleanPropertyMixin { + /** + * There is no point comparing the immutable sets in any two instances of this class, as they will always be + * the same. + */ + @Redirect(method = "equals", at = @At(value = "INVOKE", target = "Lcom/google/common/collect/ImmutableSet;equals(Ljava/lang/Object;)Z")) + private boolean skipEqualityCheck(ImmutableSet instance, Object object) { + return true; + } +} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/ModelBakeryMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/ModelBakeryMixin.java index 32afa730..7c30e699 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/ModelBakeryMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/ModelBakeryMixin.java @@ -8,6 +8,7 @@ import net.minecraft.block.BlockState; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.BlockModelShapes; import net.minecraft.client.renderer.model.*; +import net.minecraft.client.renderer.model.multipart.Selector; import net.minecraft.client.renderer.texture.SpriteMap; import net.minecraft.profiler.IProfiler; import net.minecraft.resources.IResource; @@ -38,9 +39,11 @@ import java.nio.charset.StandardCharsets; import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedDeque; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; 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; @@ -83,7 +86,8 @@ public abstract class ModelBakeryMixin { profilerIn.popPush("loadjsons"); AsyncStopwatch.measureAndLogSerialRunningTime("Parallel JSON loading", () -> { useModelCache = false; - deserializedModelCache = Minecraft.getInstance().getResourceManager().listResources("models", p -> { + this.deserializedModelCache = new ConcurrentHashMap<>(); + Collection modelLocations = Minecraft.getInstance().getResourceManager().listResources("models", p -> { if(!p.endsWith(".json")) return false; for(int i = 0; i < p.length(); i++) { @@ -91,54 +95,51 @@ public abstract class ModelBakeryMixin { return false; } return true; - }) - .parallelStream() - .map(location -> new ResourceLocation(location.getNamespace(), location.getPath().substring(7, location.getPath().length() - 5))) - .map(location -> Pair.of(location, this.loadModelSafely(location))) - .filter(pair -> pair.getSecond() != null) - .collect(Collectors.toConcurrentMap(Pair::getFirst, Pair::getSecond)); + }); + ArrayList> futures = new ArrayList<>(); + for(ResourceLocation location : modelLocations) { + futures.add(CompletableFuture.runAsync(() -> { + ResourceLocation modelPath = new ResourceLocation(location.getNamespace(), location.getPath().substring(7, location.getPath().length() - 5)); + BlockModel model = this.loadModelSafely(modelPath); + if(model != null) + this.deserializedModelCache.put(modelPath, model); + }, Util.backgroundExecutor())); + } + CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); useModelCache = true; }); AsyncStopwatch.measureAndLogSerialRunningTime("Parallel blockstate loading", () -> { ThreadLocal containerHolder = ThreadLocal.withInitial(BlockModelDefinition.ContainerHolder::new); - this.deserializedBlockstateCache = Registry.BLOCK.keySet().parallelStream() - .flatMap(block -> { - ResourceLocation blockStateJSON = new ResourceLocation(block.getNamespace(), "blockstates/" + block.getPath() + ".json"); - List blockStates; - try { - blockStates = this.resourceManager.getResources(blockStateJSON); - } catch(IOException e) { - ModernFix.LOGGER.warn("Exception loading blockstate definition: {}: {}", block, e); - blockStates = Collections.emptyList(); - } - return blockStates.stream().map(resource -> Pair.of(block, resource)); - }) - .map((pair) -> { - ResourceLocation block = pair.getFirst(); - IResource resource = pair.getSecond(); + this.deserializedBlockstateCache = new ConcurrentHashMap<>(); + ArrayList> futures = new ArrayList<>(); + for(Block block : Registry.BLOCK) { + ResourceLocation blockLocation = Registry.BLOCK.getKey(block); + futures.add(CompletableFuture.runAsync(() -> { + ResourceLocation blockStateJSON = new ResourceLocation(blockLocation.getNamespace(), "blockstates/" + blockLocation.getPath() + ".json"); + List blockStates; + try { + blockStates = this.resourceManager.getResources(blockStateJSON); + } catch(IOException e) { + ModernFix.LOGGER.warn("Exception loading blockstate definition: {}: {}", blockLocation, e); + return; + } + List> definitions = new ArrayList<>(); + StateContainer stateContainer = block.getStateDefinition(); + BlockModelDefinition.ContainerHolder context = containerHolder.get(); + context.setDefinition(stateContainer); + for(IResource resource : blockStates) { try (InputStream inputstream = resource.getInputStream()) { - BlockModelDefinition.ContainerHolder context = containerHolder.get(); - context.setDefinition(Registry.BLOCK.get(block).getStateDefinition()); - return Pair.of(block, Pair.of(resource.getSourceName(), BlockModelDefinition.fromStream(context, new InputStreamReader(inputstream, StandardCharsets.UTF_8)))); + BlockModelDefinition definition = BlockModelDefinition.fromStream(context, new InputStreamReader(inputstream, StandardCharsets.UTF_8)); + definitions.add(Pair.of(resource.getSourceName(), definition)); } catch (Exception exception1) { ModernFix.LOGGER.warn(String.format("Exception loading blockstate definition: '%s' in resourcepack: '%s': %s", resource.getLocation(), resource.getSourceName(), exception1.getMessage())); - return Pair.of(block, Pair.of((String)null, (BlockModelDefinition)null)); + return; } - }) - .filter(pair -> pair.getSecond().getSecond() != null) - .collect(Collectors.groupingBy(Pair::getFirst, Collectors.mapping(Pair::getSecond, Collectors.toList()))); - }); - AsyncStopwatch.measureAndLogSerialRunningTime("Predicate generation", () -> { - /* Pregenerate predicates */ - this.deserializedBlockstateCache.entrySet().parallelStream() - .flatMap(entry -> entry.getValue().stream() - .map(Pair::getSecond) - .map(def -> Pair.of(Registry.BLOCK.get(entry.getKey()).getStateDefinition(), def))) - .filter(pair -> pair.getSecond().isMultiPart()) - .flatMap(pair -> pair.getSecond().getMultiPart().getSelectors().stream().map(selector -> Pair.of(pair.getFirst(), selector))) - .forEach(pair -> { - pair.getSecond().getPredicate(pair.getFirst()); - }); + } + this.deserializedBlockstateCache.put(blockLocation, definitions); + }, Util.backgroundExecutor())); + } + CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); }); } diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/TransformationMatrixMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/TransformationMatrixMixin.java new file mode 100644 index 00000000..dcbd0bb1 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/TransformationMatrixMixin.java @@ -0,0 +1,31 @@ +package org.embeddedt.modernfix.mixin.perf.parallelize_model_loading; + +import net.minecraft.util.math.vector.Matrix4f; +import net.minecraft.util.math.vector.TransformationMatrix; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +import java.util.Objects; + +@Mixin(TransformationMatrix.class) +public class TransformationMatrixMixin { + @Shadow @Final private Matrix4f matrix; + private Integer cachedHashCode = null; + /** + * @author embeddedt + * @reason use cached hashcode if exists + */ + @Overwrite + public int hashCode() { + int hash; + if(cachedHashCode != null) { + hash = cachedHashCode; + } else { + hash = Objects.hashCode(this.matrix); + cachedHashCode = hash; + } + return hash; + } +} diff --git a/src/main/java/org/embeddedt/modernfix/predicate/CachedModelPredicate.java b/src/main/java/org/embeddedt/modernfix/predicate/CachedModelPredicate.java new file mode 100644 index 00000000..8c5a4566 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/predicate/CachedModelPredicate.java @@ -0,0 +1,7 @@ +package org.embeddedt.modernfix.predicate; + +/** + * Calculates the + */ +public class CachedModelPredicate { +} diff --git a/src/main/resources/modernfix.mixins.json b/src/main/resources/modernfix.mixins.json index 364bc629..47c28e97 100644 --- a/src/main/resources/modernfix.mixins.json +++ b/src/main/resources/modernfix.mixins.json @@ -37,6 +37,8 @@ "perf.parallelize_model_loading.multipart.MultipartMixin", "perf.parallelize_model_loading.multipart.VariantListMixin", "perf.parallelize_model_loading.SelectorMixin", + "perf.parallelize_model_loading.TransformationMatrixMixin", + "perf.parallelize_model_loading.BooleanPropertyMixin", "perf.trim_model_caches.ModelManagerMixin", "perf.async_jei.IngredientListElementFactoryMixin", "perf.async_jei.ClientLifecycleHandlerMixin",