Merge remote-tracking branch 'origin/main' into 1.18
This commit is contained in:
commit
2a327ef4c9
|
|
@ -6,10 +6,7 @@ import com.google.common.cache.CacheBuilder;
|
||||||
import com.google.common.cache.RemovalNotification;
|
import com.google.common.cache.RemovalNotification;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.*;
|
||||||
import com.google.gson.JsonParseException;
|
|
||||||
import com.google.gson.JsonParser;
|
|
||||||
import com.google.gson.JsonSyntaxException;
|
|
||||||
import com.mojang.datafixers.util.Pair;
|
import com.mojang.datafixers.util.Pair;
|
||||||
import com.mojang.math.Transformation;
|
import com.mojang.math.Transformation;
|
||||||
import net.minecraft.Util;
|
import net.minecraft.Util;
|
||||||
|
|
@ -25,6 +22,7 @@ import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.server.packs.resources.Resource;
|
import net.minecraft.server.packs.resources.Resource;
|
||||||
import net.minecraft.server.packs.resources.ResourceManager;
|
import net.minecraft.server.packs.resources.ResourceManager;
|
||||||
import net.minecraft.util.profiling.ProfilerFiller;
|
import net.minecraft.util.profiling.ProfilerFiller;
|
||||||
|
import net.minecraft.world.item.Item;
|
||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.level.block.state.StateDefinition;
|
import net.minecraft.world.level.block.state.StateDefinition;
|
||||||
|
|
@ -33,6 +31,8 @@ import net.minecraftforge.client.model.ForgeModelBakery;
|
||||||
import net.minecraftforge.client.model.ModelLoaderRegistry;
|
import net.minecraftforge.client.model.ModelLoaderRegistry;
|
||||||
import net.minecraftforge.common.MinecraftForge;
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
import net.minecraftforge.fml.ModLoader;
|
import net.minecraftforge.fml.ModLoader;
|
||||||
|
import net.minecraftforge.registries.ForgeRegistries;
|
||||||
|
import net.minecraftforge.registries.ForgeRegistryEntry;
|
||||||
import org.apache.commons.lang3.tuple.Triple;
|
import org.apache.commons.lang3.tuple.Triple;
|
||||||
import org.embeddedt.modernfix.ModernFix;
|
import org.embeddedt.modernfix.ModernFix;
|
||||||
import org.embeddedt.modernfix.dynamicresources.DynamicBakedModelProvider;
|
import org.embeddedt.modernfix.dynamicresources.DynamicBakedModelProvider;
|
||||||
|
|
@ -56,6 +56,7 @@ import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
@Mixin(ModelBakery.class)
|
@Mixin(ModelBakery.class)
|
||||||
public abstract class ModelBakeryMixin {
|
public abstract class ModelBakeryMixin {
|
||||||
|
|
@ -88,6 +89,7 @@ public abstract class ModelBakeryMixin {
|
||||||
@Shadow @Final public static BlockModel BLOCK_ENTITY_MARKER;
|
@Shadow @Final public static BlockModel BLOCK_ENTITY_MARKER;
|
||||||
|
|
||||||
@Shadow @Final private static Logger LOGGER;
|
@Shadow @Final private static Logger LOGGER;
|
||||||
|
|
||||||
private Cache<Triple<ResourceLocation, Transformation, Boolean>, BakedModel> loadedBakedModels;
|
private Cache<Triple<ResourceLocation, Transformation, Boolean>, BakedModel> loadedBakedModels;
|
||||||
private Cache<ResourceLocation, UnbakedModel> loadedModels;
|
private Cache<ResourceLocation, UnbakedModel> loadedModels;
|
||||||
|
|
||||||
|
|
@ -134,78 +136,145 @@ public abstract class ModelBakeryMixin {
|
||||||
|
|
||||||
private UnbakedModel missingModel;
|
private UnbakedModel missingModel;
|
||||||
|
|
||||||
/**
|
private Set<ResourceLocation> blockStateFiles;
|
||||||
* @author embeddedt
|
private Set<ResourceLocation> modelFiles;
|
||||||
* @reason don't load any models initially, just set up initial data structures
|
|
||||||
*/
|
@Redirect(method = "processLoading", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/resources/model/ModelBakery;loadBlockModel(Lnet/minecraft/resources/ResourceLocation;)Lnet/minecraft/client/renderer/block/model/BlockModel;", ordinal = 0))
|
||||||
@Overwrite(remap = false)
|
private BlockModel captureMissingModel(ModelBakery bakery, ResourceLocation location) throws IOException {
|
||||||
protected void processLoading(ProfilerFiller arg, int maxMipLevels) {
|
this.missingModel = this.loadBlockModel(location);
|
||||||
ModelLoaderRegistry.onModelLoadingStart();
|
this.blockStateFiles = new HashSet<>();
|
||||||
try {
|
this.modelFiles = new HashSet<>();
|
||||||
this.missingModel = this.loadBlockModel(MISSING_MODEL_LOCATION);
|
return (BlockModel)this.missingModel;
|
||||||
} catch (IOException var10) {
|
|
||||||
ModernFix.LOGGER.error("Error loading missing model, should never happen :(", var10);
|
|
||||||
throw new RuntimeException(var10);
|
|
||||||
}
|
|
||||||
// Gather model materials
|
|
||||||
Set<Material> initialMaterials = new HashSet<>(UNREFERENCED_TEXTURES);
|
|
||||||
gatherModelMaterials(initialMaterials);
|
|
||||||
ForgeHooksClient.gatherFluidTextures(initialMaterials);
|
|
||||||
Map<ResourceLocation, List<Material>> map = initialMaterials.stream().collect(Collectors.groupingBy(Material::atlasLocation));
|
|
||||||
this.atlasPreparations = Maps.newHashMap();
|
|
||||||
for(Map.Entry<ResourceLocation, List<Material>> entry : map.entrySet()) {
|
|
||||||
TextureAtlas atlas = new TextureAtlas(entry.getKey());
|
|
||||||
TextureAtlas.Preparations atlastexture$sheetdata = atlas.prepareToStitch(this.resourceManager, entry.getValue().stream().map(Material::texture), arg, maxMipLevels);
|
|
||||||
this.atlasPreparations.put(entry.getKey(), Pair.of(atlas, atlastexture$sheetdata));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scan the models folder and try to load, parse, and get materials from as many models as possible.
|
* @author embeddedt
|
||||||
|
* @reason don't actually load the model. instead, keep track of if we need to load a blockstate or a model,
|
||||||
|
* and save the info into the two lists
|
||||||
|
*/
|
||||||
|
@Overwrite
|
||||||
|
private void loadTopLevel(ModelResourceLocation location) {
|
||||||
|
if(Objects.equals(location.getVariant(), "inventory")) {
|
||||||
|
modelFiles.add(new ResourceLocation(location.getNamespace(), "item/" + location.getPath()));
|
||||||
|
} else {
|
||||||
|
blockStateFiles.add(new ResourceLocation(location.getNamespace(), location.getPath()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Redirect(method = "processLoading", at = @At(value = "INVOKE", target = "Lnet/minecraftforge/client/ForgeHooksClient;gatherFluidTextures(Ljava/util/Set;)V", remap = false), remap = false)
|
||||||
|
private void gatherModelTextures(Set<Material> materialSet) {
|
||||||
|
ForgeHooksClient.gatherFluidTextures(materialSet);
|
||||||
|
gatherModelMaterials(materialSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load all blockstate JSONs and model files, collect textures.
|
||||||
*/
|
*/
|
||||||
private void gatherModelMaterials(Set<Material> materialSet) {
|
private void gatherModelMaterials(Set<Material> materialSet) {
|
||||||
Stopwatch stopwatch = Stopwatch.createStarted();
|
Stopwatch stopwatch = Stopwatch.createStarted();
|
||||||
List<ResourceLocation> allModels = new ArrayList<>(this.resourceManager.listResources("models", path -> path.endsWith(".json")));
|
List<CompletableFuture<Pair<ResourceLocation, JsonElement>>> blockStateData = new ArrayList<>();
|
||||||
// for KubeJS, etc.
|
for(ResourceLocation blockstate : blockStateFiles) {
|
||||||
allModels.addAll(ResourcePackHandler.getExtraResources(this.resourceManager, "models", path -> path.endsWith(".json")));
|
blockStateData.add(CompletableFuture.supplyAsync(() -> {
|
||||||
List<CompletableFuture<Pair<ResourceLocation, JsonElement>>> modelBytes = new ArrayList<>();
|
ResourceLocation fileLocation = new ResourceLocation(blockstate.getNamespace(), "blockstates/" + blockstate.getPath() + ".json");
|
||||||
for(ResourceLocation fileLocation : allModels) {
|
|
||||||
modelBytes.add(CompletableFuture.supplyAsync(() -> {
|
|
||||||
try(Resource resource = this.resourceManager.getResource(fileLocation)) {
|
try(Resource resource = this.resourceManager.getResource(fileLocation)) {
|
||||||
JsonParser parser = new JsonParser();
|
JsonParser parser = new JsonParser();
|
||||||
// strip models/ and .json from the name
|
return Pair.of(blockstate, parser.parse(new InputStreamReader(resource.getInputStream(), StandardCharsets.UTF_8)));
|
||||||
ResourceLocation model = new ResourceLocation(fileLocation.getNamespace(), fileLocation.getPath().substring(7, fileLocation.getPath().length()-5));
|
|
||||||
return Pair.of(model, parser.parse(new InputStreamReader(resource.getInputStream(), StandardCharsets.UTF_8)));
|
|
||||||
} catch(IOException | JsonParseException e) {
|
} catch(IOException | JsonParseException e) {
|
||||||
ModernFix.LOGGER.error("Error reading model {}: {}", fileLocation, e);
|
ModernFix.LOGGER.error("Error reading blockstate {}: {}", blockstate, e);
|
||||||
return Pair.of(fileLocation, null);
|
|
||||||
}
|
}
|
||||||
|
return Pair.of(blockstate, null);
|
||||||
}, Util.backgroundExecutor()));
|
}, Util.backgroundExecutor()));
|
||||||
}
|
}
|
||||||
allModels.clear();
|
blockStateFiles = null;
|
||||||
CompletableFuture.allOf(modelBytes.toArray(new CompletableFuture[0])).join();
|
CompletableFuture.allOf(blockStateData.toArray(new CompletableFuture[0])).join();
|
||||||
Set<Pair<String, String>> errorSet = Sets.newLinkedHashSet();
|
for(CompletableFuture<Pair<ResourceLocation, JsonElement>> result : blockStateData) {
|
||||||
Map<ResourceLocation, BlockModel> basicModels = new HashMap<>();
|
Pair<ResourceLocation, JsonElement> pair = result.join();
|
||||||
try {
|
if(pair.getSecond() != null) {
|
||||||
basicModels.put(MISSING_MODEL_LOCATION, this.loadBlockModel(MISSING_MODEL_LOCATION));
|
try {
|
||||||
basicModels.put(new ResourceLocation("builtin/generated"), GENERATION_MARKER);
|
JsonObject obj = pair.getSecond().getAsJsonObject();
|
||||||
basicModels.put(new ResourceLocation("builtin/entity"), BLOCK_ENTITY_MARKER);
|
if(obj.has("variants")) {
|
||||||
} catch(IOException e) {
|
JsonObject eachVariant = obj.getAsJsonObject("variants");
|
||||||
throw new RuntimeException("Exception when populating built-in models", e);
|
for(Map.Entry<String, JsonElement> entry : eachVariant.entrySet()) {
|
||||||
}
|
JsonElement variantData = entry.getValue();
|
||||||
for(CompletableFuture<Pair<ResourceLocation, JsonElement>> future : modelBytes) {
|
List<JsonObject> variantModels;
|
||||||
Pair<ResourceLocation, JsonElement> pair = future.join();
|
if(variantData.isJsonArray()) {
|
||||||
try {
|
variantModels = new ArrayList<>();
|
||||||
if(pair.getSecond() != null) {
|
for(JsonElement model : variantData.getAsJsonArray()) {
|
||||||
BlockModel model = ModelLoaderRegistry.ExpandedBlockModelDeserializer.INSTANCE.fromJson(pair.getSecond(), BlockModel.class);
|
variantModels.add(model.getAsJsonObject());
|
||||||
model.name = pair.getFirst().toString();
|
}
|
||||||
basicModels.put(pair.getFirst(), model);
|
} else
|
||||||
|
variantModels = Collections.singletonList(variantData.getAsJsonObject());
|
||||||
|
for(JsonObject variant : variantModels) {
|
||||||
|
modelFiles.add(new ResourceLocation(variant.get("model").getAsString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
JsonArray multipartData = obj.get("multipart").getAsJsonArray();
|
||||||
|
for(JsonElement element : multipartData) {
|
||||||
|
JsonObject self = element.getAsJsonObject();
|
||||||
|
JsonElement apply = self.get("apply");
|
||||||
|
List<JsonObject> applyObjects;
|
||||||
|
if(apply.isJsonArray()) {
|
||||||
|
applyObjects = new ArrayList<>();
|
||||||
|
for(JsonElement e : apply.getAsJsonArray()) {
|
||||||
|
applyObjects.add(e.getAsJsonObject());
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
applyObjects = Collections.singletonList(apply.getAsJsonObject());
|
||||||
|
for(JsonObject applyEntry : applyObjects) {
|
||||||
|
modelFiles.add(new ResourceLocation(applyEntry.get("model").getAsString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch(RuntimeException e) {
|
||||||
|
ModernFix.LOGGER.error("Error with blockstate {}: {}", pair.getFirst(), e);
|
||||||
}
|
}
|
||||||
} catch(Throwable e) {
|
|
||||||
ModernFix.LOGGER.warn("Unable to parse {}: {}", pair.getFirst(), e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
modelBytes.clear();
|
blockStateData = null;
|
||||||
|
Map<ResourceLocation, BlockModel> basicModels = new HashMap<>();
|
||||||
|
basicModels.put(MISSING_MODEL_LOCATION, (BlockModel)missingModel);
|
||||||
|
basicModels.put(new ResourceLocation("builtin/generated"), GENERATION_MARKER);
|
||||||
|
basicModels.put(new ResourceLocation("builtin/entity"), BLOCK_ENTITY_MARKER);
|
||||||
|
Set<Pair<String, String>> errorSet = Sets.newLinkedHashSet();
|
||||||
|
while(modelFiles.size() > 0) {
|
||||||
|
List<CompletableFuture<Pair<ResourceLocation, JsonElement>>> modelBytes = new ArrayList<>();
|
||||||
|
for(ResourceLocation model : modelFiles) {
|
||||||
|
if(basicModels.containsKey(model))
|
||||||
|
continue;
|
||||||
|
ResourceLocation fileLocation = new ResourceLocation(model.getNamespace(), "models/" + model.getPath() + ".json");
|
||||||
|
modelBytes.add(CompletableFuture.supplyAsync(() -> {
|
||||||
|
try(Resource resource = this.resourceManager.getResource(fileLocation)) {
|
||||||
|
JsonParser parser = new JsonParser();
|
||||||
|
return Pair.of(model, parser.parse(new InputStreamReader(resource.getInputStream(), StandardCharsets.UTF_8)));
|
||||||
|
} catch(IOException | JsonParseException e) {
|
||||||
|
ModernFix.LOGGER.error("Error reading model {}: {}", fileLocation, e);
|
||||||
|
return Pair.of(fileLocation, null);
|
||||||
|
}
|
||||||
|
}, Util.backgroundExecutor()));
|
||||||
|
}
|
||||||
|
modelFiles.clear();
|
||||||
|
CompletableFuture.allOf(modelBytes.toArray(new CompletableFuture[0])).join();
|
||||||
|
for(CompletableFuture<Pair<ResourceLocation, JsonElement>> future : modelBytes) {
|
||||||
|
Pair<ResourceLocation, JsonElement> pair = future.join();
|
||||||
|
try {
|
||||||
|
if(pair.getSecond() != null) {
|
||||||
|
BlockModel model = ModelLoaderRegistry.ExpandedBlockModelDeserializer.INSTANCE.fromJson(pair.getSecond(), BlockModel.class);
|
||||||
|
model.name = pair.getFirst().toString();
|
||||||
|
modelFiles.addAll(model.getDependencies());
|
||||||
|
basicModels.put(pair.getFirst(), model);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} catch(Throwable e) {
|
||||||
|
ModernFix.LOGGER.warn("Unable to parse {}: {}", pair.getFirst(), e);
|
||||||
|
}
|
||||||
|
basicModels.put(pair.getFirst(), (BlockModel)missingModel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
modelFiles = null;
|
||||||
Function<ResourceLocation, UnbakedModel> modelGetter = loc -> basicModels.getOrDefault(loc, (BlockModel)this.missingModel);
|
Function<ResourceLocation, UnbakedModel> modelGetter = loc -> basicModels.getOrDefault(loc, (BlockModel)this.missingModel);
|
||||||
for(BlockModel model : basicModels.values()) {
|
for(BlockModel model : basicModels.values()) {
|
||||||
materialSet.addAll(model.getMaterials(modelGetter, errorSet));
|
materialSet.addAll(model.getMaterials(modelGetter, errorSet));
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user