Skip to content

Commit

Permalink
Fix bugs associated with custom models not using default model locations
Browse files Browse the repository at this point in the history
  • Loading branch information
Bawnorton committed Jun 24, 2023
1 parent 5f855da commit 1d098bc
Show file tree
Hide file tree
Showing 8 changed files with 214 additions and 201 deletions.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ yarn_mappings=1.20.1+build.2
loader_version=0.14.21

# Mod Properties
mod_version=1.3.0
mod_version=2.0.0
maven_group=com.bawnorton.allthetrims
archives_base_name=allthetrims

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@ public void onInitializeClient() {
}
if(stack.getItem() instanceof DyeableArmorItem dyeableArmorItem) {
if(tintIndex == 0) return dyeableArmorItem.getColor(stack);
if(tintIndex >= 2) return palette.get(MathHelper.clamp(6 - tintIndex, 0, palette.size() - 1)).getRGB();
if(tintIndex >= 2) {
return palette.get(MathHelper.clamp(6 - tintIndex, 0, palette.size() - 1)).getRGB();
}
return -1;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,139 @@
package com.bawnorton.allthetrims.mixin.client;

import com.bawnorton.allthetrims.util.ResourceHelper;
import com.bawnorton.allthetrims.AllTheTrims;
import com.bawnorton.allthetrims.compat.Compat;
import com.bawnorton.allthetrims.json.JsonHelper;
import com.bawnorton.allthetrims.util.DebugHelper;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import net.minecraft.client.render.model.BakedModelManager;
import net.minecraft.item.DyeableArmorItem;
import net.minecraft.item.ElytraItem;
import net.minecraft.item.Equipment;
import net.minecraft.item.Item;
import net.minecraft.registry.Registries;
import net.minecraft.resource.Resource;
import net.minecraft.util.Identifier;
import org.apache.commons.io.IOUtils;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;

import java.io.BufferedReader;
import java.io.IOException;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

@Mixin(BakedModelManager.class)
public abstract class BakedModelManagerMixin {
@ModifyExpressionValue(method = "method_45895(Lnet/minecraft/resource/ResourceManager;)Ljava/util/Map;", at = @At(value = "INVOKE", target = "Lnet/minecraft/resource/ResourceFinder;findResources(Lnet/minecraft/resource/ResourceManager;)Ljava/util/Map;"))
private static Map<Identifier, Resource> addTrimModels(Map<Identifier, Resource> original) {
return ResourceHelper.addTrimModels(original);
Set<Equipment> equipmentSet = new HashSet<>();
Registries.ITEM.forEach(item -> {
if (item instanceof Equipment equipment) equipmentSet.add(equipment);
});
for (Equipment equipment : equipmentSet) {
Identifier equipmentId = Registries.ITEM.getId((Item) equipment);
Identifier resourceId = new Identifier(equipmentId.getNamespace(), "models/item/" + equipmentId.getPath() + ".json");
String armourType = switch (equipment.getSlotType()) {
case HEAD -> "helmet";
case CHEST -> "chestplate";
case LEGS -> "leggings";
case FEET -> "boots";
case MAINHAND, OFFHAND -> null;
};
if (armourType == null) {
AllTheTrims.LOGGER.warn("Item " + equipmentId + "'s slot type is not an armour slot type, skipping");
continue;
}
if(Registries.ITEM.get(equipmentId) instanceof ElytraItem) {
if(Compat.isElytraTrimsLoaded()) {
armourType = "elytra";
} else {
AllTheTrims.LOGGER.warn("Item " + equipmentId + " is an elytra, but elytratrims is not loaded, skipping");
continue;
}
}
Resource resource = original.get(resourceId);
if(resource == null) {
AllTheTrims.LOGGER.warn("Could not find resource " + resourceId + " for item " + equipmentId + ", skipping");
continue;
}
try (BufferedReader reader = resource.getReader()) {
JsonObject model = JsonHelper.fromJson(reader, JsonObject.class);
if (!model.has("textures")) {
AllTheTrims.LOGGER.warn("Item " + equipmentId + "'s model does not have a textures parameter, skipping");
continue;
}

JsonObject textures = model.get("textures").getAsJsonObject();
if (!textures.has("layer0")) {
AllTheTrims.LOGGER.warn("Item " + equipmentId + "'s model does not have a layer0 texture, skipping");
continue;
}

String baseTexture = textures.get("layer0").getAsString();
JsonArray overrides = new JsonArray();
model.add("overrides", overrides);
JsonObject attOverride = new JsonObject();
attOverride.addProperty("model", baseTexture + "_att-blank_trim");
JsonObject predicate = new JsonObject();
predicate.addProperty("trim_type", 0.099);
attOverride.add("predicate", predicate);
overrides.add(attOverride);

String overrideResourceString;
if (equipment instanceof DyeableArmorItem) {
overrideResourceString = """
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "%1$s",
"layer1": "%1$s_overlay",
"layer2": "minecraft:trims/items/%2$s_trim_0_att-blank",
"layer3": "minecraft:trims/items/%2$s_trim_1_att-blank",
"layer4": "minecraft:trims/items/%2$s_trim_2_att-blank",
"layer5": "minecraft:trims/items/%2$s_trim_3_att-blank",
"layer6": "minecraft:trims/items/%2$s_trim_4_att-blank",
"layer7": "minecraft:trims/items/%2$s_trim_5_att-blank",
"layer8": "minecraft:trims/items/%2$s_trim_6_att-blank",
"layer9": "minecraft:trims/items/%2$s_trim_7_att-blank"
}
}
""".formatted(baseTexture, armourType);
} else {
overrideResourceString = """
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "%1$s",
"layer1": "minecraft:trims/items/%2$s_trim_0_att-blank",
"layer2": "minecraft:trims/items/%2$s_trim_1_att-blank",
"layer3": "minecraft:trims/items/%2$s_trim_2_att-blank",
"layer4": "minecraft:trims/items/%2$s_trim_3_att-blank",
"layer5": "minecraft:trims/items/%2$s_trim_4_att-blank",
"layer6": "minecraft:trims/items/%2$s_trim_5_att-blank",
"layer7": "minecraft:trims/items/%2$s_trim_6_att-blank",
"layer8": "minecraft:trims/items/%2$s_trim_7_att-blank"
}
}
""".formatted(baseTexture, armourType);
}

Identifier baseId = new Identifier(baseTexture);
Identifier overrideResourceModelId = baseId.withPath("models/" + baseId.getPath() + "_att-blank_trim.json");
Resource overrideResource = new Resource(resource.getPack(), () -> IOUtils.toInputStream(overrideResourceString, "UTF-8"));
original.put(overrideResourceModelId, overrideResource);
DebugHelper.createDebugFile("models", equipmentId + "_att-blank_trim.json", overrideResourceString);

resource = new Resource(resource.getPack(), () -> IOUtils.toInputStream(JsonHelper.toJson(model), "UTF-8"));
DebugHelper.createDebugFile("models", equipmentId + ".json", JsonHelper.toJson(model));
} catch (IOException e) {
throw new RuntimeException(e);
}
original.put(resourceId, resource);
}
return original;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import java.util.function.Function;

@Pseudo
@Mixin(ExtraElytraFeatureRenderer.class)
@Mixin(value = ExtraElytraFeatureRenderer.class, remap = false)
public abstract class ExtraElytraFeatureRendererMixin {
@Shadow @Final private ElytraEntityModel<?> elytra;
@Shadow @Final private static Function<Identifier, RenderLayer> ELYTRA_LAYER;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
package com.bawnorton.allthetrims.mixin.client;

import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import net.minecraft.client.render.model.json.ItemModelGenerator;
import net.minecraft.util.Util;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;

import java.util.ArrayList;
import java.util.Arrays;

@Mixin(ItemModelGenerator.class)
@Mixin(value = ItemModelGenerator.class, remap = false)
public abstract class ItemModelGeneratorMixin {
@Redirect(method = "<clinit>", at = @At(value = "INVOKE", target = "Lcom/google/common/collect/Lists;newArrayList([Ljava/lang/Object;)Ljava/util/ArrayList;"))
private static <E> ArrayList<String> increaseLayerCount(E[] elements) {
return Util.make(new ArrayList<>(), list -> {
for (int i = 0; i < 11; i++) list.add("layer" + i);
});
@ModifyExpressionValue(method = "<clinit>", at = @At(value = "INVOKE", target = "Lcom/google/common/collect/Lists;newArrayList([Ljava/lang/Object;)Ljava/util/ArrayList;"))
private static ArrayList<String> increaseLayerCount(ArrayList<String> original) {
for(int i = 5; i < 11; i++) {
if(original.contains("layer" + i)) {
continue;
}
original.add("layer" + i);
}
return original;
}
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,59 @@
package com.bawnorton.allthetrims.mixin.client;

import com.bawnorton.allthetrims.util.ResourceHelper;
import com.bawnorton.allthetrims.AllTheTrims;
import com.bawnorton.allthetrims.json.JsonHelper;
import com.bawnorton.allthetrims.util.DebugHelper;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.llamalad7.mixinextras.injector.ModifyReturnValue;
import net.minecraft.resource.NamespaceResourceManager;
import net.minecraft.resource.Resource;
import net.minecraft.util.Identifier;
import org.apache.commons.io.IOUtils;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;

import java.io.BufferedReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

@Mixin(NamespaceResourceManager.class)
public abstract class NamespaceResourceManagerMixin {
@ModifyReturnValue(method = "getAllResources", at = @At("RETURN"))
private List<Resource> replaceTrimMaterials(List<Resource> original, Identifier identifier) {
return ResourceHelper.replaceTrimMaterials(original, identifier);
if(!identifier.toString().contains("armour_trims")) return original;

List<Resource> newResources = new ArrayList<>();
for (Resource resource : original) {
try (BufferedReader reader = resource.getReader()) {
JsonObject atlas = JsonHelper.fromJson(reader, JsonObject.class);
if(!atlas.has("sources")) return original;

JsonArray sources = atlas.getAsJsonArray("sources");
if(sources.size() == 0) return original;

for(JsonElement source: sources) {
if(!(source instanceof JsonObject sourceJson)) continue;
if(!sourceJson.has("permutations")) continue;
if(!sourceJson.has("type")) continue;

String type = sourceJson.get("type").getAsString();
if(!type.equals("paletted_permutations")) continue;

JsonObject permutations = new JsonObject();
permutations.addProperty("att-blank", "trims/color_palettes/blank");
sourceJson.add("permutations", permutations);
}
newResources.add(new Resource(resource.getPack(), () -> IOUtils.toInputStream(JsonHelper.toJson(atlas), "UTF-8")));

DebugHelper.createDebugFile("atlases", resource.getResourcePackName() + "_armour_trims.json", JsonHelper.toJson(atlas));
} catch (RuntimeException | IOException e) {
AllTheTrims.LOGGER.error("Failed to modify trim atlas: " + identifier);
return original;
}
}
return newResources;
}
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
package com.bawnorton.allthetrims.mixin.client;

import com.bawnorton.allthetrims.util.DebugHelper;
import com.bawnorton.allthetrims.util.ImageUtil;
import com.bawnorton.allthetrims.util.PaletteHelper;
import com.bawnorton.allthetrims.util.ResourceHelper;
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import com.llamalad7.mixinextras.sugar.Local;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.texture.atlas.AtlasSource;
import net.minecraft.client.texture.atlas.PalettedPermutationsAtlasSource;
import net.minecraft.resource.Resource;
import net.minecraft.resource.ResourceManager;
import net.minecraft.util.Identifier;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
import org.spongepowered.asm.mixin.injection.Redirect;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.*;

@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
Expand Down Expand Up @@ -50,8 +58,29 @@ private static Optional<Resource> addBlankPalette(Optional<Resource> optionalRes
return Optional.of(new Resource(MinecraftClient.getInstance().getDefaultResourcePack(), () -> ImageUtil.toInputStream(ImageUtil.newBlankPaletteImage())));
}

@ModifyExpressionValue(method = "load", at = @At(value = "INVOKE", target = "Lnet/minecraft/resource/ResourceManager;getResource(Lnet/minecraft/util/Identifier;)Ljava/util/Optional;"))
private Optional<Resource> getLayeredTrimResource(Optional<Resource> original, ResourceManager resourceManager, @Local(name = "identifier2") Identifier identifier) {
return ResourceHelper.getLayeredTrimResource(original, resourceManager, identifier);
@Redirect(method = "load", at = @At(value = "INVOKE", target = "Lnet/minecraft/resource/ResourceManager;getResource(Lnet/minecraft/util/Identifier;)Ljava/util/Optional;"))
private Optional<Resource> getLayeredTrimResource(ResourceManager instance, Identifier identifier) {
Optional<Resource> original = instance.getResource(identifier);
if(original.isPresent()) return original;

String path = identifier.getPath();
Identifier originalIdentifier = identifier.withPath(path.substring(0, path.lastIndexOf('_')) + ".png");
Optional<Resource> optionalResource = instance.getResource(originalIdentifier);
if(optionalResource.isEmpty()) return optionalResource;

int layer = Integer.parseInt(String.valueOf(path.charAt(path.length() - "x.png".length())));
Resource resource = optionalResource.get();
try(InputStream inputStream = resource.getInputStream()) {
BufferedImage bufferedImage = ImageIO.read(inputStream);
if(bufferedImage == null) {
throw new RuntimeException("Failed to read image from " + originalIdentifier);
}
Color colour = ImageUtil.getNthDarkestColour(bufferedImage, layer);
BufferedImage newImage = ImageUtil.removeOtherColours(bufferedImage, colour);
DebugHelper.saveLayeredTexture(newImage, identifier.toString());
return Optional.of(new Resource(resource.getPack(), () -> ImageUtil.toInputStream(newImage)));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
Loading

0 comments on commit 1d098bc

Please sign in to comment.