/*
* Copyright (C) 2022-2024 NotEnoughUpdates contributors
*
* This file is part of NotEnoughUpdates.
*
* NotEnoughUpdates is free software: you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, either
* version 3 of the License, or (at your option) any later version.
*
* NotEnoughUpdates is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with NotEnoughUpdates. If not, see .
*/
package io.github.moulberry.notenoughupdates.miscgui.itemcustomization;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import io.github.moulberry.notenoughupdates.NEUManager;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
import io.github.moulberry.notenoughupdates.autosubscribe.NEUAutoSubscribe;
import io.github.moulberry.notenoughupdates.core.ChromaColour;
import io.github.moulberry.notenoughupdates.core.config.ConfigUtil;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.entity.layers.LayerArmorBase;
import net.minecraft.client.renderer.texture.DynamicTexture;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.client.resources.IResourceManagerReloadListener;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.init.Items;
import net.minecraft.item.Item;
import net.minecraft.item.ItemArmor;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.event.world.WorldEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL14;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;
import java.util.Random;
import java.util.function.Consumer;
@NEUAutoSubscribe
public class ItemCustomizeManager {
public static class ReloadListener implements IResourceManagerReloadListener {
@Override
public void onResourceManagerReload(IResourceManager resourceManager) {
ItemCustomizeManager.loadedCustomGlintTexture = false;
}
}
public static boolean disableTextureBinding = false;
private static ResourceLocation CUSTOM_GLINT_TEXTURE = new ResourceLocation(
"notenoughupdates:dynamic/custom_glint_texture");
private static boolean loadedCustomGlintTexture = false;
public static final String DEFAULT_GLINT_COLOR = ChromaColour.special(0, 0xcc, 0x6419FF);
//A050FF 0x8040cc 100,25,255 64,19
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
private static ItemDataMap itemDataMap = new ItemDataMap();
public static class ItemDataMap {
public HashMap itemData = new HashMap<>();
}
public static class ItemData {
public String customName = null;
public String customNamePrefix = "";
public boolean overrideEnchantGlint = false;
public boolean enchantGlintValue;
public String customGlintColour = DEFAULT_GLINT_COLOR;
public String customLeatherColour = null;
public String[] animatedLeatherColours = null;
public int animatedDyeTicks = 2;
public DyeMode dyeMode = DyeMode.CYCLING;
public String defaultItem = null;
public String customItem = null;
}
public static void putItemData(String uuid, ItemData data) {
itemDataMap.itemData.put(uuid, data);
}
public static void setCustomBlendFunc(String colour) {
/*int argb = ChromaColour.specialToChromaRGB(colour);
float[] hsv = Color.RGBtoHSB((argb >> 16) & 0xff, (argb >> 8) & 0xff, argb & 0xff, null);
GL14.glBlendColor(1, 1, 1, hsv[2]);*/
GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_CONSTANT_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
//GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE, GL11.GL_ONE);
}
private static void renderEffect(Consumer renderModelCallback, int color) {
GL11.glPushMatrix();
GlStateManager.enableBlend();
GlStateManager.depthMask(false);
GlStateManager.depthFunc(GL11.GL_EQUAL);
GlStateManager.disableLighting();
Minecraft.getMinecraft().getTextureManager().bindTexture(getCustomGlintTexture());
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
GlStateManager.matrixMode(5890);
GlStateManager.pushMatrix();
GlStateManager.scale(8.0F, 8.0F, 8.0F);
float f = (float) (Minecraft.getSystemTime() % 3000L) / 3000.0F / 8.0F;
GlStateManager.translate(f, 0.0F, 0.0F);
GlStateManager.rotate(-50.0F, 0.0F, 0.0F, 1.0F);
renderModelCallback.accept(color);
GlStateManager.matrixMode(5890);
GlStateManager.popMatrix();
GlStateManager.pushMatrix();
GlStateManager.scale(8.0F, 8.0F, 8.0F);
float f1 = (float) (Minecraft.getSystemTime() % 4873L) / 4873.0F / 8.0F;
GlStateManager.translate(-f1, 0.0F, 0.0F);
GlStateManager.rotate(10.0F, 0.0F, 0.0F, 1.0F);
renderModelCallback.accept(color);
GlStateManager.matrixMode(5890);
GlStateManager.popMatrix();
GlStateManager.matrixMode(5888);
GlStateManager.blendFunc(770, 771);
GlStateManager.enableLighting();
GlStateManager.depthFunc(515);
GlStateManager.depthMask(true);
Minecraft.getMinecraft().getTextureManager().bindTexture(TextureMap.locationBlocksTexture);
GL11.glPopMatrix();
}
private static void renderArmorGlint(Runnable renderModelCallback, float existed, int color) {
Minecraft.getMinecraft().getTextureManager().bindTexture(getCustomGlintTexture());
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
GlStateManager.enableBlend();
GlStateManager.depthFunc(514);
GlStateManager.depthMask(false);
float f1 = 0.5F;
GlStateManager.color(f1, f1, f1, 1.0F);
for (int i = 0; i < 2; ++i) {
GlStateManager.disableLighting();
float red = ((color >> 16) & 0xFF) / 255f;
float green = ((color >> 8) & 0xFF) / 255f;
float blue = (color & 0xFF) / 255f;
float alpha = ((color >> 24) & 0xFF) / 255f;
GlStateManager.color(red, green, blue, alpha);
GlStateManager.matrixMode(5890);
GlStateManager.loadIdentity();
float f3 = 0.33333334F;
GlStateManager.scale(f3, f3, f3);
GlStateManager.rotate(30.0F - (float) i * 60.0F, 0.0F, 0.0F, 1.0F);
GlStateManager.translate(0.0F, existed * (0.001F + (float) i * 0.003F) * 20.0F, 0.0F);
GlStateManager.matrixMode(5888);
renderModelCallback.run();
}
GlStateManager.matrixMode(5890);
GlStateManager.loadIdentity();
GlStateManager.matrixMode(5888);
GlStateManager.enableLighting();
GlStateManager.depthMask(true);
GlStateManager.depthFunc(515);
GlStateManager.disableBlend();
}
public static void pre() {
GlStateManager.matrixMode(GL11.GL_MODELVIEW);
}
public static boolean render3DGlint(String customEnchantGlint, float existed, Runnable renderModelCallback) {
if (customEnchantGlint != null) {
int colour = ChromaColour.specialToChromaRGB(customEnchantGlint);
float[] hsv = Color.RGBtoHSB((colour >> 16) & 0xff, (colour >> 8) & 0xff, colour & 0xff, null);
GL14.glBlendColor(1, 1, 1, hsv[2]);
GlStateManager.tryBlendFuncSeparate(
GL11.GL_ZERO,
GL11.GL_ONE_MINUS_SRC_ALPHA,
GL11.GL_ZERO,
GL11.GL_ONE_MINUS_SRC_ALPHA
);
int alphaValue = (int) ((1 - hsv[2] * hsv[2]) * 0xff) * ((colour >> 24) & 0xff) / 0xff;
renderArmorGlint(renderModelCallback, existed, alphaValue << 24);
GlStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE, GL11.GL_ONE);
renderArmorGlint(renderModelCallback, existed, colour);
return true;
}
return false;
}
public static boolean renderEffectHook(String customEnchantGlint, Consumer renderModelCallback) {
if (customEnchantGlint != null) {
int colour = ChromaColour.specialToChromaRGB(customEnchantGlint);
float[] hsv = Color.RGBtoHSB((colour >> 16) & 0xff, (colour >> 8) & 0xff, colour & 0xff, null);
GL14.glBlendColor(1, 1, 1, hsv[2]);
GL11.glPushMatrix();
GlStateManager.tryBlendFuncSeparate(
GL11.GL_ZERO,
GL11.GL_ONE_MINUS_SRC_ALPHA,
GL11.GL_ZERO,
GL11.GL_ONE_MINUS_SRC_ALPHA
);
int alphaValue = (int) ((1 - hsv[2] * hsv[2]) * 0xff) * ((colour >> 24) & 0xff) / 0xff;
renderEffect(renderModelCallback, alphaValue << 24);
GlStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE, GL11.GL_ONE);
renderEffect(renderModelCallback, colour);
GL11.glPopMatrix();
return true;
}
return false;
}
public static ResourceLocation getCustomGlintTexture() {
if (!loadedCustomGlintTexture) {
loadedCustomGlintTexture = true;
final ResourceLocation RES_ITEM_GLINT = new ResourceLocation("textures/misc/enchanted_item_glint.png");
try {
BufferedImage originalGlint = ImageIO.read(Minecraft
.getMinecraft()
.getResourceManager()
.getResource(RES_ITEM_GLINT)
.getInputStream());
BufferedImage newGlint = new BufferedImage(
originalGlint.getWidth(),
originalGlint.getHeight(),
BufferedImage.TYPE_INT_ARGB
);
for (int x = 0; x < originalGlint.getWidth(); x++) {
for (int y = 0; y < originalGlint.getHeight(); y++) {
int argb = originalGlint.getRGB(x, y);
int avgRGB = ((((argb >> 16) & 0xff) + ((argb >> 8) & 0xff) + (argb & 0xff)) / 3) & 0xff;
int newArgb = (avgRGB << 24) | (avgRGB << 16) | (avgRGB << 8) | avgRGB;
newGlint.setRGB(x, y, newArgb);
}
}
Minecraft.getMinecraft().getTextureManager().loadTexture(CUSTOM_GLINT_TEXTURE, new DynamicTexture(newGlint));
} catch (Exception e) {
e.printStackTrace();
CUSTOM_GLINT_TEXTURE = RES_ITEM_GLINT;
}
}
return CUSTOM_GLINT_TEXTURE;
}
public static ItemData getDataForItem(ItemStack stack) {
if (stack == null) return null;
String uuid = NEUManager.getUUIDForItem(stack);
if (uuid == null) {
return null;
} else {
return itemDataMap.itemData.get(uuid);
}
}
public static void tick() {
disableTextureBinding = false;
}
public static void loadCustomization(File file) {
itemDataMap = ConfigUtil.loadConfig(ItemDataMap.class, file, GSON);
if (itemDataMap == null) {
itemDataMap = new ItemDataMap();
}
}
public static void saveCustomization(File file) {
ConfigUtil.saveConfig(itemDataMap, file, GSON);
}
public static Item getCustomItem(ItemStack stack) {
ItemData data = getDataForItem(stack);
if (data == null || data.customItem == null || data.customItem.length() == 0 ||
data.customItem.split(":").length == 0) return stack.getItem();
Item newItem = Item.getByNameOrId(data.customItem.split(":")[0]);
if (newItem == null) return stack.getItem();
return newItem;
}
public static Item getCustomItem(ItemStack stack, String newItemString) {
if (newItemString.split(":").length == 0) return stack.getItem();
Item newItem = Item.getByNameOrId(newItemString.split(":")[0]);
if (newItem == null) return stack.getItem();
return newItem;
}
static Random random = new Random();
static HashMap lastUpdate = new HashMap<>();
static HashMap damageMap = new HashMap<>();
public static int getCustomItemDamage(ItemStack stack) {
ItemData data = getDataForItem(stack);
if (data == null || data.customItem == null || data.customItem.length() == 0) return stack.getMetadata();
try {
String damageString = data.customItem.split(":")[1];
if (damageString.equals("?")) {
ArrayList list = new ArrayList<>();
getCustomItem(stack).getSubItems(getCustomItem(stack), null, list);
if (damageMap.get(stack.getTagCompound().hashCode()) == null || System.currentTimeMillis() - lastUpdate.get(
stack.getTagCompound().hashCode()) > 250) {
damageMap.put(stack.getTagCompound().hashCode(), random.nextInt(list.size()));
lastUpdate.put(stack.getTagCompound().hashCode(), System.currentTimeMillis());
}
return damageMap.get(stack.getTagCompound().hashCode());
} else if (getCustomItem(stack) == Items.skull) {
ItemStack itemStack = NotEnoughUpdates.INSTANCE.manager.createItem(damageString.toUpperCase(Locale.ROOT).replace(" ", "_"));
if (itemStack != null && itemStack.getItem() == Items.skull) {
return 3;
}
}
return Integer.parseInt(data.customItem.split(":")[1]);
} catch (Exception e) {
if (Item.getByNameOrId(data.defaultItem) == Items.skull && getCustomItem(stack) != Items.skull) return 0;
return stack.getMetadata();
}
}
@SubscribeEvent
public void onWorldUnload(WorldEvent.Unload event) {
damageMap.clear();
lastUpdate.clear();
}
public static boolean shouldRenderLeatherColour(ItemStack stack) {
ItemData data = getDataForItem(stack);
if (data == null || data.customItem == null || data.customItem.length() == 0)
return stack.getItem() instanceof ItemArmor &&
((ItemArmor) stack.getItem()).getArmorMaterial() == ItemArmor.ArmorMaterial.LEATHER;
Item item = Item.getByNameOrId(data.customItem);
if (item == null) return stack.getItem() instanceof ItemArmor &&
((ItemArmor) stack.getItem()).getArmorMaterial() == ItemArmor.ArmorMaterial.LEATHER;
return item instanceof ItemArmor &&
((ItemArmor) item).getArmorMaterial() == ItemArmor.ArmorMaterial.LEATHER;
}
public static boolean hasCustomItem(ItemStack stack) {
ItemData data = getDataForItem(stack);
if (data == null || data.customItem == null || data.customItem.length() == 0 || data.defaultItem == null ||
data.customItem.equals(data.defaultItem) || data.customItem.split(":").length == 0) return false;
Item item = Item.getByNameOrId(data.customItem.split(":")[0]);
Item defaultItem = Item.getByNameOrId(data.defaultItem);
if (item == null) {
data.customItem = null;
return false;
}
if (item == defaultItem) {
if (ItemCustomizeManager.getCustomSkull(stack) != null) {
return true;
}
}
return defaultItem != item;
}
public static ItemStack useCustomArmour(
LayerArmorBase> instance,
EntityLivingBase entitylivingbaseIn,
int armorSlot
) {
ItemStack stack = instance.getCurrentArmor(entitylivingbaseIn, armorSlot);
if (stack == null || getDataForItem(stack) == null) return stack;
ItemStack newStack = stack.copy();
newStack.setItem(ItemCustomizeManager.getCustomItem(newStack));
newStack.setItemDamage(ItemCustomizeManager.getCustomItemDamage(newStack));
if (newStack.hasTagCompound()) {
NBTTagCompound customSkull = ItemCustomizeManager.getCustomSkull(newStack);
if (customSkull != null) {
newStack.getTagCompound().removeTag("SkullOwner");
newStack.getTagCompound().setTag("SkullOwner", customSkull);
}
}
if (armorSlot != 4 && !(newStack.getItem() instanceof ItemArmor))
// Remove non armor from any slot except heads
newStack = stack;
if (newStack.getItem() == stack.getItem()
&& newStack.getItemDamage() == stack.getItemDamage())
return stack;
return newStack;
}
public static ItemStack useCustomItem(ItemStack stack) {
if (stack == null) return stack;
if (!ItemCustomizeManager.hasCustomItem(stack)) return stack;
ItemStack newStack = stack.copy();
newStack.setItem(ItemCustomizeManager.getCustomItem(newStack));
newStack.setItemDamage(ItemCustomizeManager.getCustomItemDamage(newStack));
NBTTagCompound tagCompound = newStack.getTagCompound();
if (tagCompound != null) {
NBTTagCompound customSkull = ItemCustomizeManager.getCustomSkull(newStack);
if (customSkull != null) {
tagCompound.removeTag("SkullOwner");
tagCompound.setTag("SkullOwner", customSkull);
}
}
return newStack;
}
public static ItemStack setHeadArmour(EntityLivingBase instance, int i) {
if (instance.getCurrentArmor(3) == null) return null;
ItemStack stack = instance.getCurrentArmor(3).copy();
stack.setItem(ItemCustomizeManager.getCustomItem(stack));
stack.setItemDamage(ItemCustomizeManager.getCustomItemDamage(stack));
NBTTagCompound tagCompound = stack.getTagCompound();
if (tagCompound != null) {
NBTTagCompound customSkull = ItemCustomizeManager.getCustomSkull(stack);
if (customSkull != null) {
tagCompound.removeTag("SkullOwner");
tagCompound.setTag("SkullOwner", customSkull);
}
}
return stack;
}
public static NBTTagCompound getCustomSkull(ItemStack stack) {
ItemData data = getDataForItem(stack);
if (data == null || data.customItem == null || data.customItem.isEmpty()) return null;
try {
String damageString = data.customItem.split(":")[1];
if (getCustomItem(stack) == Items.skull) {
ItemStack itemStack = NotEnoughUpdates.INSTANCE.manager.createItem(damageString.toUpperCase(Locale.ROOT).replace(" ", "_"));
if (itemStack != null && itemStack.getItem() == Items.skull) {
return itemStack.getTagCompound().getCompoundTag("SkullOwner");
}
}
} catch (Exception ignored) {
}
return null;
}
}