Refactor armor texture management to streamline player rendering and remove redundant classes. Update mod version to 1.2.1.
This commit is contained in:
@@ -4,7 +4,7 @@ plugins {
|
||||
id 'org.spongepowered.mixin' version '0.7.+'
|
||||
}
|
||||
|
||||
version = '1.2.0'
|
||||
version = '1.2.1'
|
||||
group = 'dev.azimkin.armoryarmor'
|
||||
archivesBaseName = 'ArmoryArmor'
|
||||
def mod_id = "armory_armor"
|
||||
|
||||
@@ -1,22 +1,47 @@
|
||||
package top.azimkin.armoryarmor.client;
|
||||
|
||||
import com.mojang.blaze3d.platform.NativeImage;
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.entity.EquipmentSlot;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraftforge.registries.RegistryObject;
|
||||
import top.azimkin.armoryarmor.init.ArmoryArmorModItems;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class ArmorTextureManager {
|
||||
private static final Map<Item, ArmorTextureManager.ArmorData> armorItems = new LinkedHashMap<>();
|
||||
private static final ResourceLocation DEFAULT_TEXTURE = new ResourceLocation("armory_armor:textures/models/armor/voidarmor_layer_2.png");
|
||||
private final Map<String, PreparableTexture> textures = new ConcurrentHashMap<>();
|
||||
|
||||
public ArmorTextureManager() {
|
||||
computeArmorItems();
|
||||
}
|
||||
|
||||
public ResourceLocation getTexture(ResourceLocation playerSkin, ArmorData armorSkin) {
|
||||
//textures.clear();
|
||||
PreparableTexture data = textures.get(getKey(playerSkin, armorSkin.resourceLocation()));
|
||||
return data == null ? prepareTextureInMap(playerSkin, armorSkin) : data.rl();
|
||||
}
|
||||
|
||||
public ResourceLocation getPlayerSkinTexture(AbstractClientPlayer player) {
|
||||
return getPlayerSkinTexture(player, player.getSkinTextureLocation());
|
||||
}
|
||||
|
||||
public ResourceLocation getPlayerSkinTexture(AbstractClientPlayer player, ResourceLocation originalTexture) {
|
||||
Item slotItem = player.getItemBySlot(EquipmentSlot.LEGS).getItem();
|
||||
ArmorData data = armorItems.get(slotItem);
|
||||
if (data == null) {
|
||||
return originalTexture;
|
||||
}
|
||||
|
||||
return getTexture(originalTexture, data);
|
||||
}
|
||||
|
||||
public ResourceLocation prepareTextureInMap(ResourceLocation playerSkin, ArmorData armorSkin) {
|
||||
try (NativeImage img = TextureUtil.fromResourceLocation(playerSkin);
|
||||
NativeImage img2 = TextureUtil.fromResourceLocation(armorSkin.resourceLocation());) {
|
||||
@@ -28,8 +53,9 @@ public class ArmorTextureManager {
|
||||
TextureUtil.clearLayerPart(first, TextureUtil.SkinLayer.BODY);
|
||||
TextureUtil.clearLayerPart(first, TextureUtil.SkinLayer.LEFT_HAND);
|
||||
TextureUtil.clearLayerPart(first, TextureUtil.SkinLayer.RIGHT_HAND);
|
||||
if (armorSkin.hideHat)
|
||||
if (armorSkin.hideHat) {
|
||||
TextureUtil.clearLayerPart(first, TextureUtil.SkinLayer.HAT);
|
||||
}
|
||||
ResourceLocation rl = TextureUtil.toResourceLocation(TextureUtil.combine(first, second));
|
||||
textures.put(getKey(playerSkin, armorSkin.resourceLocation()), new PreparableTexture(rl, false));
|
||||
return rl;
|
||||
@@ -40,6 +66,25 @@ public class ArmorTextureManager {
|
||||
return playerSkin.toString() + "|" + armorSkin.toString();
|
||||
}
|
||||
|
||||
private static void fastCmpFunc(RegistryObject<? extends Item> i, String loc, boolean hideHat) {
|
||||
ResourceLocation t = ResourceLocation.tryParse(loc);
|
||||
if (t == null) t = DEFAULT_TEXTURE;
|
||||
armorItems.put(i.get(), new ArmorTextureManager.ArmorData(t, hideHat));
|
||||
}
|
||||
|
||||
private static void computeArmorItems() {
|
||||
if (!armorItems.isEmpty()) return;
|
||||
fastCmpFunc(ArmoryArmorModItems.SEAL_LEGGINGS, "armory_armor:textures/entities/seal.png", false);
|
||||
fastCmpFunc(ArmoryArmorModItems.USMC_LEGGINGS, "armory_armor:textures/entities/usmc.png", false);
|
||||
fastCmpFunc(ArmoryArmorModItems.ALQAIDA_LEGGINGS, "armory_armor:textures/entities/al-qaida.png", true);
|
||||
fastCmpFunc(ArmoryArmorModItems.ISLAMIC_LEGGINGS, "armory_armor:textures/entities/islamic_army.png", true);
|
||||
fastCmpFunc(ArmoryArmorModItems.USMC_2_LEGGINGS, "armory_armor:textures/entities/usmc2.png", false);
|
||||
fastCmpFunc(ArmoryArmorModItems.CHECHEN_1, "armory_armor:textures/entities/chechen_1.png", true);
|
||||
fastCmpFunc(ArmoryArmorModItems.CHECHEN_2, "armory_armor:textures/entities/chechen_2.png", true);
|
||||
fastCmpFunc(ArmoryArmorModItems.AL_QUAIDA_2, "armory_armor:textures/entities/al_quaida_2.png", true);
|
||||
fastCmpFunc(ArmoryArmorModItems.AL_QUAIDA_3, "armory_armor:textures/entities/al_quaida_3.png", true);
|
||||
}
|
||||
|
||||
public record PreparableTexture(ResourceLocation rl, boolean isCompleted) {}
|
||||
public record ArmorData(ResourceLocation resourceLocation, boolean hideHat) {}
|
||||
}
|
||||
|
||||
@@ -79,37 +79,6 @@ public class TextureUtil {
|
||||
}
|
||||
}
|
||||
return null;
|
||||
/*int texId = texture.getId();
|
||||
GlStateManager._bindTexture(texId);
|
||||
|
||||
int width = 64; // standard skin width
|
||||
int height = 64; // standard skin height
|
||||
|
||||
ByteBuffer buffer = MemoryUtil.memAlloc(width * height * 4);
|
||||
GL11.glGetTexImage(GL11.GL_TEXTURE_2D, 0, GL12.GL_BGRA, GL11.GL_UNSIGNED_BYTE, buffer);
|
||||
|
||||
byte[] bytes = new byte[buffer.remaining()];
|
||||
buffer.get(bytes);
|
||||
MemoryUtil.memFree(buffer);
|
||||
|
||||
// Convert bytes to NativeImage if needed
|
||||
NativeImage image = new NativeImage(width, height, false);
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
int i = (y * width + x) * 4;
|
||||
|
||||
int b = buffer.get(i) & 0xFF;
|
||||
int g = buffer.get(i+1) & 0xFF;
|
||||
int r = buffer.get(i+2) & 0xFF;
|
||||
int a = buffer.get(i+3) & 0xFF;
|
||||
|
||||
int argb = (a << 24) | (r << 16) | (g << 8) | b;
|
||||
image.setPixelRGBA(x, y, argb);
|
||||
}
|
||||
}
|
||||
MemoryUtil.memFree(buffer);
|
||||
return image;*/
|
||||
|
||||
}
|
||||
|
||||
public static BufferedImage combine(BufferedImage image1, BufferedImage image2) {
|
||||
@@ -120,20 +89,17 @@ public class TextureUtil {
|
||||
}
|
||||
|
||||
public static void clearLayerPart(BufferedImage image, SkinLayer layer) {
|
||||
//Graphics2D g2d = image.createGraphics();
|
||||
//g2d.setComposite(AlphaComposite.Clear);
|
||||
clearArea(image, layer.firstArea);
|
||||
clearArea(image, layer.secondArea);
|
||||
//g2d.dispose();
|
||||
clearArea(image, layer.areas);
|
||||
}
|
||||
|
||||
private static void clearArea(BufferedImage image, Area area) {
|
||||
for (int x = area.x1; x < area.x2; x++) {
|
||||
for (int y = area.y1; y < area.y2; y++) {
|
||||
image.setRGB(x, y, 0);
|
||||
private static void clearArea(BufferedImage image, Area... areas) {
|
||||
for (var area : areas) {
|
||||
for (int x = area.x1; x <= area.x2; x++) {
|
||||
for (int y = area.y1; y <= area.y2; y++) {
|
||||
image.setRGB(x, y, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
//g2d.fillRect(area.x1, area.y1, area.x1-area.x2, area.y1-area.y2);
|
||||
}
|
||||
|
||||
public static ResourceLocation toResourceLocation(BufferedImage image) {
|
||||
@@ -154,10 +120,9 @@ public class TextureUtil {
|
||||
LEFT_FEET(new Area(4, 48, 11, 51), new Area(0, 52, 15, 63)),
|
||||
RIGHT_FEET(new Area(4, 32, 11, 35), new Area(0, 36, 15, 47)),
|
||||
HAT(new Area(40, 0, 55, 7), new Area(32, 8, 63, 15));
|
||||
public final Area firstArea, secondArea;
|
||||
SkinLayer(Area firstArea, Area secondArea) {
|
||||
this.firstArea = firstArea;
|
||||
this.secondArea = secondArea;
|
||||
public final Area[] areas;
|
||||
SkinLayer(Area... areas) {
|
||||
this.areas = areas;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package top.azimkin.armoryarmor.mixin;
|
||||
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import top.azimkin.armoryarmor.client.ArmorTextureManager;
|
||||
|
||||
@Mixin(AbstractClientPlayer.class)
|
||||
public class AbstractClientPlayerMixin {
|
||||
@Unique
|
||||
private final ArmorTextureManager armoryArmor$manager = new ArmorTextureManager();
|
||||
|
||||
@Inject(method = "getSkinTextureLocation", at = {@At("TAIL")}, cancellable = true)
|
||||
public void getSkinTextureLocation(CallbackInfoReturnable<ResourceLocation> cir) {
|
||||
cir.setReturnValue(armoryArmor$manager.getPlayerSkinTexture((AbstractClientPlayer) (Object) this, cir.getReturnValue()));
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package top.azimkin.armoryarmor.mixin;
|
||||
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import net.minecraft.client.renderer.entity.player.PlayerRenderer;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import top.azimkin.armoryarmor.client.InfoHolder;
|
||||
|
||||
@Mixin(PlayerRenderer.class)
|
||||
public class PlayerRenderMixin {
|
||||
@Inject(method = "getTextureLocation(Lnet/minecraft/client/player/AbstractClientPlayer;)Lnet/minecraft/resources/ResourceLocation;", at = @At(value = "HEAD"), cancellable = true)
|
||||
public void getTextureLocation(AbstractClientPlayer p_117783_, CallbackInfoReturnable<ResourceLocation> cir) {
|
||||
if (InfoHolder.TOP_TEXTURE == null) return;
|
||||
cir.setReturnValue(InfoHolder.TOP_TEXTURE);
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
package top.azimkin.armoryarmor.procedures;
|
||||
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraftforge.client.event.RenderPlayerEvent;
|
||||
import net.minecraftforge.eventbus.api.EventPriority;
|
||||
import net.minecraftforge.registries.RegistryObject;
|
||||
import top.azimkin.armoryarmor.client.ArmorTextureManager;
|
||||
import top.azimkin.armoryarmor.client.InfoHolder;
|
||||
import top.azimkin.armoryarmor.init.ArmoryArmorModItems;
|
||||
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.client.event.RenderLivingEvent;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
|
||||
import net.minecraft.world.entity.EquipmentSlot;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Mod.EventBusSubscriber(value = {Dist.CLIENT})
|
||||
public class RenderEventProcedure {
|
||||
private static final Map<Item, ArmorTextureManager.ArmorData> armorItems = new LinkedHashMap<>();
|
||||
private static final ResourceLocation DEFAULT_TEXTURE = new ResourceLocation("armory_armor:textures/models/armor/voidarmor_layer_2.png");
|
||||
private static final ArmorTextureManager manager = new ArmorTextureManager();
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
@SubscribeEvent(priority = EventPriority.HIGHEST)
|
||||
public static void onEventTriggeredPre(RenderPlayerEvent.Pre event) {
|
||||
computeArmorItems();
|
||||
AbstractClientPlayer player = (AbstractClientPlayer) event.getEntity();
|
||||
Item slotItem = player.getItemBySlot(EquipmentSlot.LEGS).getItem();
|
||||
ArmorTextureManager.ArmorData data = armorItems.get(slotItem);
|
||||
if (data == null) {
|
||||
InfoHolder.TOP_TEXTURE = null;
|
||||
return;
|
||||
}
|
||||
|
||||
InfoHolder.TOP_TEXTURE = manager.getTexture(player.getSkinTextureLocation(), data);
|
||||
}
|
||||
|
||||
private static void fastCmpFunc(RegistryObject<? extends Item> i, String loc, boolean hideHat) {
|
||||
ResourceLocation t = ResourceLocation.tryParse(loc);
|
||||
if (t == null) t = DEFAULT_TEXTURE;
|
||||
RenderEventProcedure.armorItems.put(i.get(), new ArmorTextureManager.ArmorData(t, hideHat));
|
||||
}
|
||||
|
||||
private static void computeArmorItems() {
|
||||
if (!armorItems.isEmpty()) return;
|
||||
fastCmpFunc(ArmoryArmorModItems.SEAL_LEGGINGS,"armory_armor:textures/entities/seal.png", false);
|
||||
fastCmpFunc(ArmoryArmorModItems.USMC_LEGGINGS,"armory_armor:textures/entities/usmc.png", false);
|
||||
fastCmpFunc(ArmoryArmorModItems.ALQAIDA_LEGGINGS,"armory_armor:textures/entities/al-qaida.png", true);
|
||||
fastCmpFunc(ArmoryArmorModItems.ISLAMIC_LEGGINGS,"armory_armor:textures/entities/islamic_army.png", true);
|
||||
fastCmpFunc(ArmoryArmorModItems.USMC_2_LEGGINGS,"armory_armor:textures/entities/usmc2.png", false);
|
||||
fastCmpFunc(ArmoryArmorModItems.CHECHEN_1,"armory_armor:textures/entities/chechen_1.png", true);
|
||||
fastCmpFunc(ArmoryArmorModItems.CHECHEN_2,"armory_armor:textures/entities/chechen_2.png", true);
|
||||
fastCmpFunc(ArmoryArmorModItems.AL_QUAIDA_2,"armory_armor:textures/entities/al_quaida_2.png", true);
|
||||
fastCmpFunc(ArmoryArmorModItems.AL_QUAIDA_3,"armory_armor:textures/entities/al_quaida_3.png", true);
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
"refmap": "armory_armor.refmap.json",
|
||||
"mixins": [],
|
||||
"client": [
|
||||
"PlayerRenderMixin"
|
||||
"AbstractClientPlayerMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
|
||||
Reference in New Issue
Block a user