Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use a single datagen cache for all entrypoints. #4339

Draft
wants to merge 3 commits into
base: 1.21.4
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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<EntrypointContainer<DataGeneratorEntrypoint>> dataGeneratorInitializers = FabricLoader.getInstance()
Expand All @@ -119,6 +122,9 @@ private static void runInternal() {
Object2IntOpenHashMap<String> jsonKeySortOrders = (Object2IntOpenHashMap<String>) DataProvider.JSON_KEY_SORT_ORDER;
Object2IntOpenHashMap<String> defaultJsonKeySortOrders = new Object2IntOpenHashMap<>(jsonKeySortOrders);

final Set<String> providerNames = new HashSet<>();
var dataCache = new DataCache(outputDir, providerNames, SharedConstants.getGameVersion());

for (EntrypointContainer<DataGeneratorEntrypoint> entrypointContainer : dataGeneratorInitializers) {
final String id = entrypointContainer.getProvider().getMetadata().getId();

Expand Down Expand Up @@ -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);
Expand All @@ -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<DataGeneratorEntrypoint> dataGeneratorInitializers) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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<String> providerNames;

public FabricDataGeneratorImpl(Path output, ModContainer mod, boolean strictValidation, CompletableFuture<RegistryWrapper.WrapperLookup> registriesFuture, DataCache dataCache, Set<String> providerNames) {
super(output, mod, strictValidation, registriesFuture);
this.dataCache = dataCache;
this.providerNames = providerNames;
}

public DataCache getDataCache() {
return dataCache;
}

public Set<String> getProviderNames() {
return providerNames;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<Map.Entry<Path, HashCode>> sortPaths(ImmutableSet<Map.Entry<Path, HashCode>> original) {
return original.stream()
.sorted(Map.Entry.comparingByKey(Comparator.comparing(k -> normalizePath(k.toString()))))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<Path> paths;

@Shadow
@Final
private Map<String, DataCache.CachedData> 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<String> providerNames = dataGenerator.getProviderNames();

for (String providerName : providerNames) {
Path path = getPath(providerName);
paths.add(path);
cachedDatas.put(providerName, parseOrCreateCache(root, path));
}

totalSize += providerNames.size();
}
}
Original file line number Diff line number Diff line change
@@ -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<String> providerNames, GameVersion gameVersion, Operation<DataCache> 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<Void> original) {
if ((Object) (this) instanceof FabricDataGeneratorImpl) {
// Skip this for now, we will run it for all data generators in FabricDataGenHelper
return;
}

original.call(instance);
}
}
Original file line number Diff line number Diff line change
@@ -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<String> addProvider(DataGenerator instance, Operation<Set<String>> original) {
if ((Object) (instance) instanceof FabricDataGeneratorImpl fabricDataGenerator) {
return fabricDataGenerator.getProviderNames();
}

return original.call(instance);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
"mixins": [
"DataCacheCachedDataMixin",
"DataCacheMixin",
"DataGeneratorMixin",
"DataGeneratorPackMixin",
"DataProviderMixin",
"TagBuilderMixin",
"TagProviderMixin",
Expand Down
Original file line number Diff line number Diff line change
@@ -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();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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"
]
}
}
Loading
Loading