diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 90cd7e6690..912d813741 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -78,4 +78,7 @@ jobs: distribution: 'microsoft' java-version: '21' - run: ./gradlew generateResources --stacktrace --warning-mode=fail - - run: if [ -n "$(git status --porcelain)" ]; then exit 1; fi + - run: | + git add -A + git status + if [ -n "$(git status --porcelain)" ]; then exit 1; fi diff --git a/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/api/datagen/v1/FabricDataGenerator.java b/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/api/datagen/v1/FabricDataGenerator.java index 6105255c57..3d0ff5368a 100644 --- a/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/api/datagen/v1/FabricDataGenerator.java +++ b/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/api/datagen/v1/FabricDataGenerator.java @@ -36,7 +36,8 @@ /** * An extension to vanilla's {@link DataGenerator} providing mod specific data, and helper functions. */ -public final class FabricDataGenerator extends DataGenerator { +@ApiStatus.NonExtendable +public abstract class FabricDataGenerator extends DataGenerator { private final ModContainer modContainer; private final boolean strictValidation; private final FabricDataOutput fabricOutput; diff --git a/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/impl/datagen/FabricDataCache.java b/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/impl/datagen/FabricDataCache.java new file mode 100644 index 0000000000..eb9fdbd005 --- /dev/null +++ b/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/impl/datagen/FabricDataCache.java @@ -0,0 +1,21 @@ +/* + * 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.impl.datagen; + +public interface FabricDataCache { + void fabric_prepare(FabricDataGeneratorImpl dataGenerator); +} diff --git a/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/impl/datagen/FabricDataGenHelper.java b/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/impl/datagen/FabricDataGenHelper.java index edee955b3e..5cd7fc19e3 100644 --- a/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/impl/datagen/FabricDataGenHelper.java +++ b/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/impl/datagen/FabricDataGenHelper.java @@ -16,6 +16,7 @@ package net.fabricmc.fabric.impl.datagen; +import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; @@ -26,6 +27,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.concurrent.CompletableFuture; import com.google.gson.JsonObject; @@ -38,6 +40,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import net.minecraft.SharedConstants; +import net.minecraft.data.DataCache; import net.minecraft.data.DataProvider; import net.minecraft.registry.BuiltinRegistries; import net.minecraft.registry.DynamicRegistryManager; @@ -50,7 +54,6 @@ import net.minecraft.util.Util; import net.fabricmc.fabric.api.datagen.v1.DataGeneratorEntrypoint; -import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator; import net.fabricmc.fabric.api.event.registry.DynamicRegistries; import net.fabricmc.fabric.api.resource.conditions.v1.ResourceCondition; import net.fabricmc.fabric.api.resource.conditions.v1.ResourceConditions; @@ -101,7 +104,7 @@ public static void run() { } } - private static void runInternal() { + private static void runInternal() throws IOException { Path outputDir = Paths.get(Objects.requireNonNull(OUTPUT_DIR, "No output dir provided with the 'fabric-api.datagen.output-dir' property")); List> dataGeneratorInitializers = FabricLoader.getInstance() @@ -119,6 +122,9 @@ private static void runInternal() { Object2IntOpenHashMap jsonKeySortOrders = (Object2IntOpenHashMap) DataProvider.JSON_KEY_SORT_ORDER; Object2IntOpenHashMap defaultJsonKeySortOrders = new Object2IntOpenHashMap<>(jsonKeySortOrders); + final Set providerNames = new HashSet<>(); + var dataCache = new DataCache(outputDir, providerNames, SharedConstants.getGameVersion()); + for (EntrypointContainer entrypointContainer : dataGeneratorInitializers) { final String id = entrypointContainer.getProvider().getMetadata().getId(); @@ -146,8 +152,9 @@ private static void runInternal() { modContainer = FabricLoader.getInstance().getModContainer(effectiveModId).orElseThrow(() -> new RuntimeException("Failed to find effective mod container for mod id (%s)".formatted(effectiveModId))); } - FabricDataGenerator dataGenerator = new FabricDataGenerator(outputDir, modContainer, STRICT_VALIDATION, registriesFuture); + var dataGenerator = new FabricDataGeneratorImpl(outputDir, modContainer, STRICT_VALIDATION, registriesFuture, dataCache, providerNames); entrypoint.onInitializeDataGenerator(dataGenerator); + ((FabricDataCache) (dataCache)).fabric_prepare(dataGenerator); dataGenerator.run(); jsonKeySortOrders.keySet().removeAll(keys); @@ -156,6 +163,8 @@ private static void runInternal() { throw new RuntimeException("Failed to run data generator from mod (%s)".formatted(id), t); } } + + dataCache.write(); } private static RegistryWrapper.WrapperLookup createRegistryWrapper(List dataGeneratorInitializers) { diff --git a/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/impl/datagen/FabricDataGeneratorImpl.java b/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/impl/datagen/FabricDataGeneratorImpl.java new file mode 100644 index 0000000000..f2a80d95d2 --- /dev/null +++ b/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/impl/datagen/FabricDataGeneratorImpl.java @@ -0,0 +1,46 @@ +/* + * 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.impl.datagen; + +import java.nio.file.Path; +import java.util.Set; +import java.util.concurrent.CompletableFuture; + +import net.minecraft.data.DataCache; +import net.minecraft.registry.RegistryWrapper; + +import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator; +import net.fabricmc.loader.api.ModContainer; + +public class FabricDataGeneratorImpl extends FabricDataGenerator { + private final DataCache dataCache; + private final Set providerNames; + + public FabricDataGeneratorImpl(Path output, ModContainer mod, boolean strictValidation, CompletableFuture registriesFuture, DataCache dataCache, Set providerNames) { + super(output, mod, strictValidation, registriesFuture); + this.dataCache = dataCache; + this.providerNames = providerNames; + } + + public DataCache getDataCache() { + return dataCache; + } + + public Set getProviderNames() { + return providerNames; + } +} 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 ed2bc7b0d8..c399e115aa 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 @@ -27,9 +27,11 @@ import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; -@Mixin(targets = "net.minecraft.data.DataCache$CachedData") +import net.minecraft.data.DataCache; + +@Mixin(DataCache.CachedData.class) public abstract class DataCacheCachedDataMixin { - @ModifyExpressionValue(method = "write", at = @At(value = "INVOKE", target = "Lcom/google/common/collect/ImmutableMap;entrySet()Lcom/google/common/collect/ImmutableSet;")) + @ModifyExpressionValue(method = "write", at = @At(value = "INVOKE", target = "Lcom/google/common/collect/ImmutableMap;entrySet()Lcom/google/common/collect/ImmutableSet;", remap = false)) private ImmutableSet> sortPaths(ImmutableSet> original) { return original.stream() .sorted(Map.Entry.comparingByKey(Comparator.comparing(k -> normalizePath(k.toString())))) 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 ef7d371271..2dcf45e08d 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 @@ -16,20 +16,67 @@ package net.fabricmc.fabric.mixin.datagen; +import java.nio.file.Path; import java.time.LocalDateTime; +import java.util.Map; +import java.util.Set; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; import net.minecraft.data.DataCache; +import net.fabricmc.fabric.impl.datagen.FabricDataCache; +import net.fabricmc.fabric.impl.datagen.FabricDataGeneratorImpl; + @Mixin(DataCache.class) -public abstract class DataCacheMixin { +abstract class DataCacheMixin implements FabricDataCache { + @Shadow + @Final + Set paths; + + @Shadow + @Final + private Map cachedDatas; + + @Shadow + @Final + private Path root; + + @Shadow + @Final + @Mutable + private int totalSize; + + @Shadow + protected abstract Path getPath(String providerName); + + @Shadow + private static DataCache.CachedData parseOrCreateCache(Path root, Path dataProviderPath) { + throw new IllegalStateException(); + } + // 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; } + + @Override + public void fabric_prepare(FabricDataGeneratorImpl dataGenerator) { + Set providerNames = dataGenerator.getProviderNames(); + + for (String providerName : providerNames) { + Path path = getPath(providerName); + paths.add(path); + cachedDatas.put(providerName, parseOrCreateCache(root, path)); + } + + totalSize += providerNames.size(); + } } diff --git a/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/mixin/datagen/DataGeneratorMixin.java b/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/mixin/datagen/DataGeneratorMixin.java new file mode 100644 index 0000000000..29f1df4640 --- /dev/null +++ b/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/mixin/datagen/DataGeneratorMixin.java @@ -0,0 +1,53 @@ +/* + * 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.Collection; + +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.injection.At; + +import net.minecraft.GameVersion; +import net.minecraft.data.DataCache; +import net.minecraft.data.DataGenerator; + +import net.fabricmc.fabric.impl.datagen.FabricDataGeneratorImpl; + +@Mixin(DataGenerator.class) +public class DataGeneratorMixin { + @WrapOperation(method = "run", at = @At(value = "NEW", target = "(Ljava/nio/file/Path;Ljava/util/Collection;Lnet/minecraft/GameVersion;)Lnet/minecraft/data/DataCache;")) + private DataCache newDataCache(Path root, Collection providerNames, GameVersion gameVersion, Operation original) { + if ((Object) (this) instanceof FabricDataGeneratorImpl fabricDataGenerator) { + return fabricDataGenerator.getDataCache(); + } + + return original.call(root, providerNames, gameVersion); + } + + @WrapOperation(method = "run", at = @At(value = "INVOKE", target = "Lnet/minecraft/data/DataCache;write()V")) + private void dataCacheWrite(DataCache instance, Operation original) { + if ((Object) (this) instanceof FabricDataGeneratorImpl) { + // Skip this for now, we will run it for all data generators in FabricDataGenHelper + return; + } + + original.call(instance); + } +} diff --git a/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/mixin/datagen/DataGeneratorPackMixin.java b/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/mixin/datagen/DataGeneratorPackMixin.java new file mode 100644 index 0000000000..b830980088 --- /dev/null +++ b/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/mixin/datagen/DataGeneratorPackMixin.java @@ -0,0 +1,40 @@ +/* + * 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.util.Set; + +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.injection.At; + +import net.minecraft.data.DataGenerator; + +import net.fabricmc.fabric.impl.datagen.FabricDataGeneratorImpl; + +@Mixin(DataGenerator.Pack.class) +public class DataGeneratorPackMixin { + @WrapOperation(method = "addProvider", at = @At(value = "FIELD", target = "Lnet/minecraft/data/DataGenerator;providerNames:Ljava/util/Set;")) + private Set addProvider(DataGenerator instance, Operation> original) { + if ((Object) (instance) instanceof FabricDataGeneratorImpl fabricDataGenerator) { + return fabricDataGenerator.getProviderNames(); + } + + return original.call(instance); + } +} diff --git a/fabric-data-generation-api-v1/src/main/resources/fabric-data-generation-api-v1.accesswidener b/fabric-data-generation-api-v1/src/main/resources/fabric-data-generation-api-v1.accesswidener index 4fea74e6fe..01003a4bf9 100644 --- a/fabric-data-generation-api-v1/src/main/resources/fabric-data-generation-api-v1.accesswidener +++ b/fabric-data-generation-api-v1/src/main/resources/fabric-data-generation-api-v1.accesswidener @@ -56,6 +56,8 @@ transitive-accessible class net/minecraft/client/data/BlockStateModelGenerator$C accessible class net/minecraft/client/data/ModelProvider$ItemAssets accessible class net/minecraft/client/data/ModelProvider$BlockStateSuppliers +accessible class net/minecraft/data/DataCache$CachedData + ### Generated access wideners below transitive-accessible method net/minecraft/data/recipe/RecipeGenerator generate ()V 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 0c65f720e7..bebe091791 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 @@ -5,6 +5,8 @@ "mixins": [ "DataCacheCachedDataMixin", "DataCacheMixin", + "DataGeneratorMixin", + "DataGeneratorPackMixin", "DataProviderMixin", "TagBuilderMixin", "TagProviderMixin", diff --git a/fabric-data-generation-api-v1/src/testmod/java/net/fabricmc/fabric/test/datagen/DataGeneratorEmptyTestEntrypoint.java b/fabric-data-generation-api-v1/src/testmod/java/net/fabricmc/fabric/test/datagen/DataGeneratorEmptyTestEntrypoint.java new file mode 100644 index 0000000000..0dee950344 --- /dev/null +++ b/fabric-data-generation-api-v1/src/testmod/java/net/fabricmc/fabric/test/datagen/DataGeneratorEmptyTestEntrypoint.java @@ -0,0 +1,27 @@ +/* + * 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.test.datagen; + +import net.fabricmc.fabric.api.datagen.v1.DataGeneratorEntrypoint; +import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator; + +public class DataGeneratorEmptyTestEntrypoint implements DataGeneratorEntrypoint { + @Override + public void onInitializeDataGenerator(FabricDataGenerator dataGenerator) { + final FabricDataGenerator.Pack pack = dataGenerator.createPack(); + } +} diff --git a/fabric-data-generation-api-v1/src/testmod/resources/fabric.mod.json b/fabric-data-generation-api-v1/src/testmod/resources/fabric.mod.json index 0815fc9efd..06ba689edb 100644 --- a/fabric-data-generation-api-v1/src/testmod/resources/fabric.mod.json +++ b/fabric-data-generation-api-v1/src/testmod/resources/fabric.mod.json @@ -12,7 +12,8 @@ "net.fabricmc.fabric.test.datagen.DataGeneratorTestContent" ], "fabric-datagen": [ - "net.fabricmc.fabric.test.datagen.DataGeneratorTestEntrypoint" + "net.fabricmc.fabric.test.datagen.DataGeneratorTestEntrypoint", + "net.fabricmc.fabric.test.datagen.DataGeneratorEmptyTestEntrypoint" ] } } diff --git a/fabric-data-generation-api-v1/template.accesswidener b/fabric-data-generation-api-v1/template.accesswidener index 578f3e7e0b..395c4a40d8 100644 --- a/fabric-data-generation-api-v1/template.accesswidener +++ b/fabric-data-generation-api-v1/template.accesswidener @@ -51,4 +51,6 @@ transitive-accessible class net/minecraft/client/data/BlockStateModelGenerator$C accessible class net/minecraft/client/data/ModelProvider$ItemAssets accessible class net/minecraft/client/data/ModelProvider$BlockStateSuppliers +accessible class net/minecraft/data/DataCache$CachedData + ### Generated access wideners below