package net.minecraft.client.renderer.entity.layers; import com.mojang.blaze3d.vertex.PoseStack; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import java.io.IOException; import java.util.Optional; import java.util.function.UnaryOperator; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.Util; import net.minecraft.client.model.EntityModel; import net.minecraft.client.model.VillagerLikeModel; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.entity.RenderLayerParent; import net.minecraft.client.renderer.entity.state.LivingEntityRenderState; import net.minecraft.client.renderer.entity.state.VillagerDataHolderRenderState; import net.minecraft.client.renderer.texture.MissingTextureAtlasSprite; import net.minecraft.client.resources.metadata.animation.VillagerMetadataSection; import net.minecraft.core.Holder; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.resources.ResourceManager; import net.minecraft.util.Mth; import net.minecraft.world.entity.npc.VillagerData; import net.minecraft.world.entity.npc.VillagerProfession; import net.minecraft.world.entity.npc.VillagerType; @Environment(EnvType.CLIENT) public class VillagerProfessionLayer & VillagerLikeModel> extends RenderLayer { private static final Int2ObjectMap LEVEL_LOCATIONS = Util.make(new Int2ObjectOpenHashMap<>(), int2ObjectOpenHashMap -> { int2ObjectOpenHashMap.put(1, ResourceLocation.withDefaultNamespace("stone")); int2ObjectOpenHashMap.put(2, ResourceLocation.withDefaultNamespace("iron")); int2ObjectOpenHashMap.put(3, ResourceLocation.withDefaultNamespace("gold")); int2ObjectOpenHashMap.put(4, ResourceLocation.withDefaultNamespace("emerald")); int2ObjectOpenHashMap.put(5, ResourceLocation.withDefaultNamespace("diamond")); }); private final Object2ObjectMap, VillagerMetadataSection.Hat> typeHatCache = new Object2ObjectOpenHashMap<>(); private final Object2ObjectMap, VillagerMetadataSection.Hat> professionHatCache = new Object2ObjectOpenHashMap<>(); private final ResourceManager resourceManager; private final String path; public VillagerProfessionLayer(RenderLayerParent renderer, ResourceManager resourceManager, String path) { super(renderer); this.resourceManager = resourceManager; this.path = path; } public void render(PoseStack poseStack, MultiBufferSource multiBufferSource, int i, S livingEntityRenderState, float f, float g) { if (!livingEntityRenderState.isInvisible) { VillagerData villagerData = livingEntityRenderState.getVillagerData(); if (villagerData != null) { Holder holder = villagerData.type(); Holder holder2 = villagerData.profession(); VillagerMetadataSection.Hat hat = this.getHatData(this.typeHatCache, "type", holder); VillagerMetadataSection.Hat hat2 = this.getHatData(this.professionHatCache, "profession", holder2); M entityModel = this.getParentModel(); entityModel.hatVisible(hat2 == VillagerMetadataSection.Hat.NONE || hat2 == VillagerMetadataSection.Hat.PARTIAL && hat != VillagerMetadataSection.Hat.FULL); ResourceLocation resourceLocation = this.getResourceLocation("type", holder); renderColoredCutoutModel(entityModel, resourceLocation, poseStack, multiBufferSource, i, livingEntityRenderState, -1); entityModel.hatVisible(true); if (!holder2.is(VillagerProfession.NONE) && !livingEntityRenderState.isBaby) { ResourceLocation resourceLocation2 = this.getResourceLocation("profession", holder2); renderColoredCutoutModel(entityModel, resourceLocation2, poseStack, multiBufferSource, i, livingEntityRenderState, -1); if (!holder2.is(VillagerProfession.NITWIT)) { ResourceLocation resourceLocation3 = this.getResourceLocation( "profession_level", LEVEL_LOCATIONS.get(Mth.clamp(villagerData.level(), 1, LEVEL_LOCATIONS.size())) ); renderColoredCutoutModel(entityModel, resourceLocation3, poseStack, multiBufferSource, i, livingEntityRenderState, -1); } } } } } private ResourceLocation getResourceLocation(String folder, ResourceLocation location) { return location.withPath((UnaryOperator)(string2 -> "textures/entity/" + this.path + "/" + folder + "/" + string2 + ".png")); } private ResourceLocation getResourceLocation(String folder, Holder holder) { return (ResourceLocation)holder.unwrapKey() .map(resourceKey -> this.getResourceLocation(folder, resourceKey.location())) .orElse(MissingTextureAtlasSprite.getLocation()); } public VillagerMetadataSection.Hat getHatData(Object2ObjectMap, VillagerMetadataSection.Hat> cache, String folder, Holder key) { ResourceKey resourceKey = (ResourceKey)key.unwrapKey().orElse(null); return resourceKey == null ? VillagerMetadataSection.Hat.NONE : cache.computeIfAbsent( resourceKey, object -> (VillagerMetadataSection.Hat)this.resourceManager.getResource(this.getResourceLocation(folder, resourceKey.location())).flatMap(resource -> { try { return resource.metadata().getSection(VillagerMetadataSection.TYPE).map(VillagerMetadataSection::hat); } catch (IOException var2) { return Optional.empty(); } }).orElse(VillagerMetadataSection.Hat.NONE) ); } }