From d687c627a47e1a1d0b5e9989aa834375f55009fa Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Sat, 30 Nov 2024 13:28:44 +0000 Subject: [PATCH 1/3] Make data generation .cache file reproducible --- .../fabric/mixin/datagen/DataCacheMixin.java | 35 +++++++++++++++++++ .../fabric-data-generation-api-v1.mixins.json | 1 + 2 files changed, 36 insertions(+) create mode 100644 fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/mixin/datagen/DataCacheMixin.java diff --git a/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/mixin/datagen/DataCacheMixin.java b/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/mixin/datagen/DataCacheMixin.java new file mode 100644 index 0000000000..96b4291748 --- /dev/null +++ b/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/mixin/datagen/DataCacheMixin.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.mixin.datagen; + +import java.time.LocalDateTime; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import net.minecraft.data.DataCache; + +@Mixin(DataCache.class) +public class DataCacheMixin { + // Lambda in write()V + @Redirect(method = "method_46571", at = @At(value = "INVOKE", target = "Ljava/time/LocalDateTime;now()Ljava/time/LocalDateTime;")) + private LocalDateTime constantTime() { + // Write a constant time to the .cache file to ensure datagen output is reproducible + return LocalDateTime.MIN; + } +} diff --git a/fabric-data-generation-api-v1/src/main/resources/fabric-data-generation-api-v1.mixins.json b/fabric-data-generation-api-v1/src/main/resources/fabric-data-generation-api-v1.mixins.json index b778d9e4c3..e7b08bed4c 100644 --- a/fabric-data-generation-api-v1/src/main/resources/fabric-data-generation-api-v1.mixins.json +++ b/fabric-data-generation-api-v1/src/main/resources/fabric-data-generation-api-v1.mixins.json @@ -3,6 +3,7 @@ "package": "net.fabricmc.fabric.mixin.datagen", "compatibilityLevel": "JAVA_21", "mixins": [ + "DataCacheMixin", "DataProviderMixin", "TagBuilderMixin", "TagProviderMixin", From 6074cf50c47561f6f5d23872245e3105672c89ac Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Sat, 30 Nov 2024 13:47:36 +0000 Subject: [PATCH 2/3] Make the cache even more reproducable. Thanks https://github.com/Gaming32/bingo/blob/b8a38e10efee9b830650f1cf69259214a9911e4d/fabric/src/main/java/io/github/gaming32/bingo/mixin/fabric/MixinHashCache_ProviderCache.java --- .../datagen/DataCacheCachedDataMixin.java | 50 +++++++++++++++++++ .../fabric/mixin/datagen/DataCacheMixin.java | 2 +- .../fabric-data-generation-api-v1.mixins.json | 1 + 3 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/mixin/datagen/DataCacheCachedDataMixin.java diff --git a/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/mixin/datagen/DataCacheCachedDataMixin.java b/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/mixin/datagen/DataCacheCachedDataMixin.java new file mode 100644 index 0000000000..76b886d940 --- /dev/null +++ b/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/mixin/datagen/DataCacheCachedDataMixin.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.mixin.datagen; + +import java.nio.file.Path; +import java.util.Comparator; +import java.util.Map; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.hash.HashCode; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(targets = "net.minecraft.data.DataCache$CachedData") +public abstract class DataCacheCachedDataMixin { + @WrapOperation(method = "write", at = @At(value = "INVOKE", target = "Lcom/google/common/collect/ImmutableMap;entrySet()Lcom/google/common/collect/ImmutableSet;")) + private ImmutableSet> sortPaths(ImmutableMap instance, Operation>> original) { + return original.call(instance).stream() + .sorted(Map.Entry.comparingByKey(Comparator.comparing(k -> normalizePath(k.toString())))) + .collect(ImmutableSet.toImmutableSet()); + } + + @WrapOperation(method = "write", at = @At(value = "INVOKE", target = "Ljava/nio/file/Path;toString()Ljava/lang/String;")) + private String pathToString(Path instance, Operation original) { + return normalizePath(original.call(instance)); + } + + @Unique + private static String normalizePath(String path) { + return path.replace('\\', '/'); + } +} diff --git a/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/mixin/datagen/DataCacheMixin.java b/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/mixin/datagen/DataCacheMixin.java index 96b4291748..ef7d371271 100644 --- a/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/mixin/datagen/DataCacheMixin.java +++ b/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/mixin/datagen/DataCacheMixin.java @@ -25,7 +25,7 @@ import net.minecraft.data.DataCache; @Mixin(DataCache.class) -public class DataCacheMixin { +public abstract class DataCacheMixin { // Lambda in write()V @Redirect(method = "method_46571", at = @At(value = "INVOKE", target = "Ljava/time/LocalDateTime;now()Ljava/time/LocalDateTime;")) private LocalDateTime constantTime() { diff --git a/fabric-data-generation-api-v1/src/main/resources/fabric-data-generation-api-v1.mixins.json b/fabric-data-generation-api-v1/src/main/resources/fabric-data-generation-api-v1.mixins.json index e7b08bed4c..0c65f720e7 100644 --- a/fabric-data-generation-api-v1/src/main/resources/fabric-data-generation-api-v1.mixins.json +++ b/fabric-data-generation-api-v1/src/main/resources/fabric-data-generation-api-v1.mixins.json @@ -3,6 +3,7 @@ "package": "net.fabricmc.fabric.mixin.datagen", "compatibilityLevel": "JAVA_21", "mixins": [ + "DataCacheCachedDataMixin", "DataCacheMixin", "DataProviderMixin", "TagBuilderMixin", From 5349231fe4ad3eb9bdb2d4f2216ca3368f9c228f Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Sat, 30 Nov 2024 16:28:43 +0000 Subject: [PATCH 3/3] Use ModifyExpressionValue --- .../mixin/datagen/DataCacheCachedDataMixin.java | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/mixin/datagen/DataCacheCachedDataMixin.java b/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/mixin/datagen/DataCacheCachedDataMixin.java index 76b886d940..ed2bc7b0d8 100644 --- a/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/mixin/datagen/DataCacheCachedDataMixin.java +++ b/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/mixin/datagen/DataCacheCachedDataMixin.java @@ -20,27 +20,25 @@ import java.util.Comparator; import java.util.Map; -import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.hash.HashCode; -import com.llamalad7.mixinextras.injector.wrapoperation.Operation; -import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; @Mixin(targets = "net.minecraft.data.DataCache$CachedData") public abstract class DataCacheCachedDataMixin { - @WrapOperation(method = "write", at = @At(value = "INVOKE", target = "Lcom/google/common/collect/ImmutableMap;entrySet()Lcom/google/common/collect/ImmutableSet;")) - private ImmutableSet> sortPaths(ImmutableMap instance, Operation>> original) { - return original.call(instance).stream() + @ModifyExpressionValue(method = "write", at = @At(value = "INVOKE", target = "Lcom/google/common/collect/ImmutableMap;entrySet()Lcom/google/common/collect/ImmutableSet;")) + private ImmutableSet> sortPaths(ImmutableSet> original) { + return original.stream() .sorted(Map.Entry.comparingByKey(Comparator.comparing(k -> normalizePath(k.toString())))) .collect(ImmutableSet.toImmutableSet()); } - @WrapOperation(method = "write", at = @At(value = "INVOKE", target = "Ljava/nio/file/Path;toString()Ljava/lang/String;")) - private String pathToString(Path instance, Operation original) { - return normalizePath(original.call(instance)); + @ModifyExpressionValue(method = "write", at = @At(value = "INVOKE", target = "Ljava/nio/file/Path;toString()Ljava/lang/String;")) + private String pathToString(String original) { + return normalizePath(original); } @Unique