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.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import com.google.gson.*;
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import com.mojang.math.Transformation;
|
||||
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.ResourceManager;
|
||||
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.state.BlockState;
|
||||
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.common.MinecraftForge;
|
||||
import net.minecraftforge.fml.ModLoader;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
import net.minecraftforge.registries.ForgeRegistryEntry;
|
||||
import org.apache.commons.lang3.tuple.Triple;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
import org.embeddedt.modernfix.dynamicresources.DynamicBakedModelProvider;
|
||||
|
|
@ -56,6 +56,7 @@ import java.util.concurrent.CompletableFuture;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@Mixin(ModelBakery.class)
|
||||
public abstract class ModelBakeryMixin {
|
||||
|
|
@ -88,6 +89,7 @@ public abstract class ModelBakeryMixin {
|
|||
@Shadow @Final public static BlockModel BLOCK_ENTITY_MARKER;
|
||||
|
||||
@Shadow @Final private static Logger LOGGER;
|
||||
|
||||
private Cache<Triple<ResourceLocation, Transformation, Boolean>, BakedModel> loadedBakedModels;
|
||||
private Cache<ResourceLocation, UnbakedModel> loadedModels;
|
||||
|
||||
|
|
@ -134,78 +136,145 @@ public abstract class ModelBakeryMixin {
|
|||
|
||||
private UnbakedModel missingModel;
|
||||
|
||||
/**
|
||||
* @author embeddedt
|
||||
* @reason don't load any models initially, just set up initial data structures
|
||||
*/
|
||||
@Overwrite(remap = false)
|
||||
protected void processLoading(ProfilerFiller arg, int maxMipLevels) {
|
||||
ModelLoaderRegistry.onModelLoadingStart();
|
||||
try {
|
||||
this.missingModel = this.loadBlockModel(MISSING_MODEL_LOCATION);
|
||||
} 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));
|
||||
}
|
||||
private Set<ResourceLocation> blockStateFiles;
|
||||
private Set<ResourceLocation> modelFiles;
|
||||
|
||||
@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))
|
||||
private BlockModel captureMissingModel(ModelBakery bakery, ResourceLocation location) throws IOException {
|
||||
this.missingModel = this.loadBlockModel(location);
|
||||
this.blockStateFiles = new HashSet<>();
|
||||
this.modelFiles = new HashSet<>();
|
||||
return (BlockModel)this.missingModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
Stopwatch stopwatch = Stopwatch.createStarted();
|
||||
List<ResourceLocation> allModels = new ArrayList<>(this.resourceManager.listResources("models", path -> path.endsWith(".json")));
|
||||
// for KubeJS, etc.
|
||||
allModels.addAll(ResourcePackHandler.getExtraResources(this.resourceManager, "models", path -> path.endsWith(".json")));
|
||||
List<CompletableFuture<Pair<ResourceLocation, JsonElement>>> modelBytes = new ArrayList<>();
|
||||
for(ResourceLocation fileLocation : allModels) {
|
||||
modelBytes.add(CompletableFuture.supplyAsync(() -> {
|
||||
List<CompletableFuture<Pair<ResourceLocation, JsonElement>>> blockStateData = new ArrayList<>();
|
||||
for(ResourceLocation blockstate : blockStateFiles) {
|
||||
blockStateData.add(CompletableFuture.supplyAsync(() -> {
|
||||
ResourceLocation fileLocation = new ResourceLocation(blockstate.getNamespace(), "blockstates/" + blockstate.getPath() + ".json");
|
||||
try(Resource resource = this.resourceManager.getResource(fileLocation)) {
|
||||
JsonParser parser = new JsonParser();
|
||||
// strip models/ and .json from the name
|
||||
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)));
|
||||
return Pair.of(blockstate, 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);
|
||||
ModernFix.LOGGER.error("Error reading blockstate {}: {}", blockstate, e);
|
||||
}
|
||||
return Pair.of(blockstate, null);
|
||||
}, Util.backgroundExecutor()));
|
||||
}
|
||||
allModels.clear();
|
||||
CompletableFuture.allOf(modelBytes.toArray(new CompletableFuture[0])).join();
|
||||
Set<Pair<String, String>> errorSet = Sets.newLinkedHashSet();
|
||||
Map<ResourceLocation, BlockModel> basicModels = new HashMap<>();
|
||||
try {
|
||||
basicModels.put(MISSING_MODEL_LOCATION, this.loadBlockModel(MISSING_MODEL_LOCATION));
|
||||
basicModels.put(new ResourceLocation("builtin/generated"), GENERATION_MARKER);
|
||||
basicModels.put(new ResourceLocation("builtin/entity"), BLOCK_ENTITY_MARKER);
|
||||
} catch(IOException e) {
|
||||
throw new RuntimeException("Exception when populating built-in models", e);
|
||||
}
|
||||
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();
|
||||
basicModels.put(pair.getFirst(), model);
|
||||
blockStateFiles = null;
|
||||
CompletableFuture.allOf(blockStateData.toArray(new CompletableFuture[0])).join();
|
||||
for(CompletableFuture<Pair<ResourceLocation, JsonElement>> result : blockStateData) {
|
||||
Pair<ResourceLocation, JsonElement> pair = result.join();
|
||||
if(pair.getSecond() != null) {
|
||||
try {
|
||||
JsonObject obj = pair.getSecond().getAsJsonObject();
|
||||
if(obj.has("variants")) {
|
||||
JsonObject eachVariant = obj.getAsJsonObject("variants");
|
||||
for(Map.Entry<String, JsonElement> entry : eachVariant.entrySet()) {
|
||||
JsonElement variantData = entry.getValue();
|
||||
List<JsonObject> variantModels;
|
||||
if(variantData.isJsonArray()) {
|
||||
variantModels = new ArrayList<>();
|
||||
for(JsonElement model : variantData.getAsJsonArray()) {
|
||||
variantModels.add(model.getAsJsonObject());
|
||||
}
|
||||
} 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);
|
||||
for(BlockModel model : basicModels.values()) {
|
||||
materialSet.addAll(model.getMaterials(modelGetter, errorSet));
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user