Подписывайтесь на наш Telegram и не пропускайте важные новости! Перейти

Визуальная часть TargetHud | Javelin / Mendix

Начинающий
Начинающий
Статус
Оффлайн
Регистрация
1 Ноя 2025
Сообщения
15
Реакции
0
Выберите загрузчик игры
  1. Forge
  2. NeoForge
  3. ForgeOptiFine
SS Снизу
Короче вроде норм, но через нейронку

1771018202220.png




TargetHudComponent:
Expand Collapse Copy
package fun.mendix.client.hud.elements.component;

import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gl.ShaderProgramKeys;
import net.minecraft.client.gui.screen.ChatScreen;
import net.minecraft.client.network.PlayerListEntry;
import net.minecraft.client.render.*;
import net.minecraft.client.texture.Sprite;
import net.minecraft.client.util.DefaultSkinHelper;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.effect.StatusEffectInstance;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.RotationAxis;
import org.joml.Matrix4f;
import ru.nexusguard.protection.annotations.Native;
import fun.mendix.Mendix;
import fun.mendix.base.animations.base.Animation;
import fun.mendix.base.animations.base.Easing;
import fun.mendix.base.font.Fonts;
import fun.mendix.base.font.MsdfRenderer;
import fun.mendix.base.theme.Theme;
import fun.mendix.client.hud.elements.draggable.DraggableHudElement;
import fun.mendix.client.modules.impl.combat.Aura;
import fun.mendix.client.modules.impl.misc.NameProtect;
import fun.mendix.client.modules.impl.misc.ScoreboardHealth;
import fun.mendix.utility.game.player.PlayerIntersectionUtil;
import fun.mendix.utility.mixin.accessors.DrawContextAccessor;
import fun.mendix.utility.render.display.base.BorderRadius;
import fun.mendix.utility.render.display.base.CustomDrawContext;
import fun.mendix.utility.render.display.base.color.ColorRGBA;
import fun.mendix.utility.render.display.shader.DrawUtil;

import java.util.*;

public class TargetHudComponent extends DraggableHudElement {

   // ========== КОНСТАНТЫ ==========
   private static final float WIDTH = 130F;
   private static final float HEIGHT = 46F;
   private static final float PADDING = 6F;
   private static final float HEAD_SIZE = 28F;
   private static final float BAR_HEIGHT = 4F;
   private static final float BAR_RADIUS = 2F;
   private static final float OUTLINE_WIDTH = 1.8F;
   private static final float ARMOR_ICON_SIZE = 10F;
   private static final float ARMOR_SCALE = 0.65F;
   private static final float EFFECT_ICON_SIZE = 14F;
   private static final long FADE_DURATION = 250L;
   private static final long HEALTH_LAG_DURATION = 700L;
   private static final long ITEM_SPIN_DURATION = 400L;

   // ========== ЧАСТИЦЫ УРОНА ==========
   private static final float SHAKE_INTENSITY = 2.0F;
   private static final int PARTICLE_COUNT_PER_HURT = 4;
   private static final int PARTICLE_LIFETIME = 12;
   private static final float PARTICLE_SPEED = 1.8F;
   private static final Random RANDOM = new Random();

   // ========== АНИМАЦИИ ==========
   private final Animation fadeAnimation = new Animation(FADE_DURATION, Easing.SINE_OUT);
   private final Animation healthAnimation = new Animation(300L, Easing.CUBIC_OUT);
   private final Animation lagHealthAnimation = new Animation(HEALTH_LAG_DURATION, Easing.CUBIC_OUT);
   private final Animation absorptionAnimation = new Animation(250L, Easing.CUBIC_OUT);
   private final Animation itemSpinAnimation = new Animation(ITEM_SPIN_DURATION, Easing.BACK_OUT);
   private final Animation headPopAnimation = new Animation(200L, Easing.BACK_OUT);
   private final Animation hpPulseAnimation = new Animation(600L, Easing.SINE_IN_OUT);

   // ========== СОСТОЯНИЕ ==========
   private LivingEntity target;
   private final Map<UUID, Identifier> skinCache = new HashMap<>();
   private final List<Particle> particles = new ArrayList<>();

   // ========== КОНСТРУКТОР ==========
   public TargetHudComponent(String name, float initialX, float initialY, float windowWidth, float windowHeight,
                             float offsetX, float offsetY, DraggableHudElement.Align align) {
      super(name, initialX, initialY, windowWidth, windowHeight, offsetX, offsetY, align);
   }

   // ========== ОСНОВНОЙ РЕНДЕР ==========
   @Native
   public void render(CustomDrawContext ctx) {
      Aura aura = Aura.INSTANCE;
      LivingEntity newTarget = (mc.currentScreen instanceof ChatScreen) ? mc.player : aura.getTarget();

      updateTargetState(newTarget);
      fadeAnimation.update(target != null);
      headPopAnimation.update(target != null);

      float fade = fadeAnimation.getValue();
      if (fade < 0.01F) return;

      if (target != null) {
         renderTargetHud(ctx, target, fade);
      }
   }

   private void updateTargetState(LivingEntity newTarget) {
      if (newTarget == null) {
         target = null;
         particles.clear();
      } else {
         if (target != newTarget) {
            target = newTarget;
            particles.clear();
            healthAnimation.reset();
            lagHealthAnimation.reset();
            absorptionAnimation.reset();
            itemSpinAnimation.reset();
            itemSpinAnimation.setValue(1.0F);
            headPopAnimation.reset();
            headPopAnimation.setValue(1.0F);

            float maxHealth = target.getMaxHealth();
            float health = ScoreboardHealth.INSTANCE.isEnabled()
                    ? PlayerIntersectionUtil.getHealth(target)
                    : target.getHealth();
            healthAnimation.setValue(health / maxHealth);
            lagHealthAnimation.setValue(health / maxHealth);
            absorptionAnimation.setValue(target.getAbsorptionAmount() / maxHealth);
         }
      }
   }

   // ========== РЕНДЕР ХУДА ==========
   @Native
   private void renderTargetHud(CustomDrawContext ctx, LivingEntity target, float fade) {
      Theme theme = Mendix.getInstance().getThemeManager().getCurrentTheme();
      ColorRGBA themeColor = theme.getColor();
      ColorRGBA themeSecond = theme.getSecondColor();

      float x = this.x;
      float y = this.y;
      float contentX = x + PADDING + HEAD_SIZE + 6F;
      float contentWidth = WIDTH - (PADDING + HEAD_SIZE + 6F) - PADDING;
      float contentY = y + PADDING;

      // --- ТЕНЬ ПОД ХУДОМ ---
      DrawUtil.drawRoundedRect(ctx.getMatrices(), x + 2, y + 2, WIDTH, HEIGHT,
              BorderRadius.all(8F), new ColorRGBA(0, 0, 0, 60 * fade));

      // --- ФОН (СТЕКЛО) ---
      DrawUtil.drawBlur(ctx.getMatrices(), x, y, WIDTH, HEIGHT, 12F,
              BorderRadius.all(8F), new ColorRGBA(80, 80, 80, 160 * fade));
      DrawUtil.drawRoundedRect(ctx.getMatrices(), x, y, WIDTH, HEIGHT,
              BorderRadius.all(8F), new ColorRGBA(10, 10, 10, 220 * fade));

      // --- ОБВОДКА — ЦВЕТ ТЕМЫ (ХАРАКТЕРНЫЙ ТЕМЕ) ---
      ColorRGBA borderColor = themeColor.mix(themeSecond, 0.5F).withAlpha(255 * fade);
      DrawUtil.drawRoundedBorder(ctx.getMatrices(), x, y, WIDTH, HEIGHT, OUTLINE_WIDTH,
              BorderRadius.all(8F), borderColor);

      // --- АВАТАРКА ---
      Identifier skin = getSkinTexture(target);
      float headSize = HEAD_SIZE * (0.9F + 0.1F * headPopAnimation.getValue());
      float headX = x + PADDING + (HEAD_SIZE - headSize) / 2;
      float headY = y + PADDING + (HEAD_SIZE - headSize) / 2;

      DrawUtil.drawRoundedRect(ctx.getMatrices(), headX - 2, headY - 2, headSize + 4, headSize + 4,
              BorderRadius.all(8F), themeColor.withAlpha(80 * fade));

      boolean isHurt = target.hurtTime > 0;
      if (isHurt) {
         ctx.getMatrices().push();
         float shakeX = (RANDOM.nextFloat() - 0.5F) * SHAKE_INTENSITY;
         float shakeY = (RANDOM.nextFloat() - 0.5F) * SHAKE_INTENSITY;
         ctx.getMatrices().translate(shakeX, shakeY, 0);
         spawnDamageParticles(headX + headSize / 2, headY + headSize / 2, themeColor);
      }

      DrawUtil.drawPlayerHeadWithRoundedShader(ctx.getMatrices(), skin,
              headX, headY, headSize,
              BorderRadius.all(6F), ColorRGBA.WHITE.withAlpha(255 * fade));

      if (isHurt) {
         ctx.getMatrices().pop();
      }

      updateParticles();
      renderParticles(ctx, ctx.getMatrices(), fade);

      // --- ИМЯ ЦЕЛИ ---
      String name = (target == mc.player && NameProtect.INSTANCE.isEnabled())
              ? NameProtect.getCustomName()
              : target.getNameForScoreboard();

      MsdfRenderer.renderText(Fonts.BOLD, name, 9F,
              new ColorRGBA(0, 0, 0, 100 * fade).getRGB(),
              ctx.getMatrices().peek().getPositionMatrix(),
              contentX + 1, contentY + 1F, 0F, true, 0.7F, 1F, contentWidth);
      MsdfRenderer.renderText(Fonts.BOLD, name, 9F,
              ColorRGBA.WHITE.withAlpha(255 * fade).getRGB(),
              ctx.getMatrices().peek().getPositionMatrix(),
              contentX, contentY, 0F, true, 0.7F, 1F, contentWidth);

      // --- РАССТОЯНИЕ ---
      if (mc.player != null) {
         float dist = mc.player.distanceTo(target);
         String distText = String.format(Locale.US, "%.1f м", dist);
         MsdfRenderer.renderText(Fonts.REGULAR, distText, 7F,
                 new ColorRGBA(180, 180, 180, 200 * fade).getRGB(),
                 ctx.getMatrices().peek().getPositionMatrix(),
                 contentX, contentY + 10F, 0F, true, 0.7F, 1F, contentWidth);
      }

      // --- ПОЛОСКА ЗДОРОВЬЯ ---
      float maxHealth = target.getMaxHealth();
      float health = ScoreboardHealth.INSTANCE.isEnabled()
              ? PlayerIntersectionUtil.getHealth(target)
              : target.getHealth();
      float healthPercentCurrent = health / maxHealth;
      float absorptionPercent = target.getAbsorptionAmount() / maxHealth;

      healthAnimation.update(healthPercentCurrent);
      absorptionAnimation.update(absorptionPercent);

      if (lagHealthAnimation.getValue() > healthPercentCurrent) {
         lagHealthAnimation.update(healthPercentCurrent);
      } else {
         lagHealthAnimation.setValue(healthPercentCurrent);
      }

      float barY = y + HEIGHT - PADDING - BAR_HEIGHT;

      DrawUtil.drawRoundedRect(ctx.getMatrices(), contentX, barY, contentWidth, BAR_HEIGHT,
              BorderRadius.all(BAR_RADIUS), new ColorRGBA(20, 20, 20, 255 * fade));

      float lagWidth = contentWidth * lagHealthAnimation.getValue();
      if (lagWidth > 0) {
         DrawUtil.drawRoundedRect(ctx.getMatrices(), contentX, barY, lagWidth, BAR_HEIGHT,
                 BorderRadius.all(BAR_RADIUS), new ColorRGBA(150, 50, 50, 150 * fade));
      }

      float healthWidth = contentWidth * healthAnimation.getValue();
      if (healthWidth > 0) {
         ColorRGBA healthColor1 = interpolateColorGradient(healthPercentCurrent);
         ColorRGBA healthColor2 = healthColor1.darker(0.8F);
         DrawUtil.drawRoundedRect(ctx.getMatrices(), contentX, barY, healthWidth, BAR_HEIGHT,
                 BorderRadius.all(BAR_RADIUS),
                 healthColor1.withAlpha(255 * fade), healthColor1.withAlpha(255 * fade),
                 healthColor2.withAlpha(255 * fade), healthColor2.withAlpha(255 * fade));
      }

      hpPulseAnimation.update(healthPercentCurrent < 0.2F);
      float pulseGlow = hpPulseAnimation.getValue() * 0.3F;
      if (healthPercentCurrent < 0.2F) {
         DrawUtil.drawRoundedRect(ctx.getMatrices(),
                 contentX - 1, barY - 1, healthWidth + 2, BAR_HEIGHT + 2,
                 BorderRadius.all(BAR_RADIUS + 1),
                 new ColorRGBA(255, 50, 50, (int)(80 * fade * pulseGlow)));
      }

      float absorptionWidth = contentWidth * absorptionAnimation.getValue();
      if (absorptionWidth > 0) {
         float sparkle = (MathHelper.sin(mc.player.age * 0.3F) * 0.5F + 0.5F) * 0.5F + 0.5F;
         DrawUtil.drawRoundedRect(ctx.getMatrices(),
                 contentX, barY - 1.5F, absorptionWidth, 2.5F,
                 BorderRadius.all(1.5F),
                 new ColorRGBA(255, 215, 0, (int)(200 * fade * sparkle)));
      }

      // --- ТЕКСТ HP — СПРАВА НАД ПОЛОСКОЙ ---
      String hpText = String.format(Locale.US, "%.0f", health);
      float hpFontSize = 6F;
      float hpWidth = Fonts.REGULAR.getFont(hpFontSize).width(hpText);
      float hpX = contentX + contentWidth - hpWidth - 2F;
      float hpY = barY - 8F;

      ctx.drawText(Fonts.REGULAR.getFont(hpFontSize), hpText,
              hpX + 1, hpY + 1,
              new ColorRGBA(0, 0, 0, 100 * fade));
      ctx.drawText(Fonts.REGULAR.getFont(hpFontSize), hpText,
              hpX, hpY,
              ColorRGBA.WHITE.withAlpha(230 * fade));

      // --- БРОНЯ ---
      if (target instanceof PlayerEntity) {
         renderArmorAndItems(ctx, (PlayerEntity) target, x, y + HEIGHT + 4F, WIDTH, fade);
      }

      this.width = WIDTH;
      this.height = HEIGHT;
   }

   // ========== ЦВЕТ ЗДОРОВЬЯ ==========
   private ColorRGBA interpolateColorGradient(float percent) {
      if (percent > 0.8F) return new ColorRGBA(50, 255, 50);
      if (percent > 0.5F) return new ColorRGBA(255, 255, 50);
      if (percent > 0.2F) return new ColorRGBA(255, 150, 50);
      return new ColorRGBA(255, 50, 50);
   }

   // ========== ЧАСТИЦЫ УРОНА ==========
   private void spawnDamageParticles(float centerX, float centerY, ColorRGBA themeColor) {
      ColorRGBA baseColor = themeColor.mix(ColorRGBA.RED, 0.5F);

      for (int i = 0; i < PARTICLE_COUNT_PER_HURT; i++) {
         float angle = RANDOM.nextFloat() * (float) Math.PI * 2;
         float speed = PARTICLE_SPEED * (0.7F + RANDOM.nextFloat() * 0.6F);
         float vx = (float) Math.cos(angle) * speed;
         float vy = (float) Math.sin(angle) * speed - 0.5F;

         int lifetime = PARTICLE_LIFETIME + RANDOM.nextInt(6) - 3;
         float variation = 0.8F + RANDOM.nextFloat() * 0.4F;

         int r = (int) MathHelper.clamp(baseColor.getRed() * variation, 0, 255);
         int g = (int) MathHelper.clamp(baseColor.getGreen() * variation, 0, 255);
         int b = (int) MathHelper.clamp(baseColor.getBlue() * variation, 0, 255);
         int a = baseColor.getAlpha();

         ColorRGBA particleColor = new ColorRGBA(r, g, b, a);
         particles.add(new Particle(centerX, centerY, vx, vy, lifetime, particleColor));
      }
   }

   private void updateParticles() {
      particles.removeIf(p -> {
         p.update();
         return !p.isAlive();
      });
   }

   private void renderParticles(CustomDrawContext ctx, MatrixStack matrices, float fade) {
      if (particles.isEmpty()) return;

      RenderSystem.enableBlend();
      RenderSystem.defaultBlendFunc();
      RenderSystem.disableDepthTest();
      RenderSystem.depthMask(false);
      RenderSystem.setShader(ShaderProgramKeys.POSITION_COLOR);

      Matrix4f matrix = matrices.peek().getPositionMatrix();
      BufferBuilder buffer = Tessellator.getInstance().begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR);

      for (Particle p : particles) {
         float alpha = (float) p.life / p.maxLife * fade;
         int a = (int) (alpha * 255);
         int color = p.color.withAlpha(a).getRGB();

         float size = 1.5F + (1.0F - (float) p.life / p.maxLife) * 1.0F;
         float x1 = p.x - size;
         float y1 = p.y - size;
         float x2 = p.x + size;
         float y2 = p.y + size;

         int r = (color >> 16) & 0xFF;
         int g = (color >> 8) & 0xFF;
         int b = color & 0xFF;
         int a2 = (color >> 24) & 0xFF;

         buffer.vertex(matrix, x1, y2, 0).color(r, g, b, a2);
         buffer.vertex(matrix, x2, y2, 0).color(r, g, b, a2);
         buffer.vertex(matrix, x2, y1, 0).color(r, g, b, a2);
         buffer.vertex(matrix, x1, y1, 0).color(r, g, b, a2);
      }

      BufferRenderer.drawWithGlobalProgram(buffer.end());

      RenderSystem.enableDepthTest();
      RenderSystem.depthMask(true);
      RenderSystem.disableBlend();
   }

   // ========== БРОНЯ И ПРЕДМЕТЫ ==========
   private void renderArmorAndItems(CustomDrawContext ctx, PlayerEntity player, float baseX, float baseY, float hudWidth, float fade) {
      List<ItemStack> armor = player.getInventory().armor;
      ItemStack[] items = {
              player.getMainHandStack(),
              player.getOffHandStack(),
              armor.get(3),
              armor.get(2),
              armor.get(1),
              armor.get(0)
      };

      int count = 0;
      for (ItemStack stack : items) if (!stack.isEmpty()) count++;
      if (count == 0) return;

      float totalWidth = count * ARMOR_ICON_SIZE;
      float startX = baseX + (hudWidth - totalWidth) / 2F;
      float currentX = startX;

      DrawUtil.drawRoundedRect(ctx.getMatrices(),
              startX - 3, baseY - 2,
              totalWidth + 6, ARMOR_ICON_SIZE + 4,
              BorderRadius.all(4F),
              new ColorRGBA(20, 20, 20, 150 * fade));

      itemSpinAnimation.update(true);
      float spin = itemSpinAnimation.getValue();

      for (ItemStack stack : items) {
         if (!stack.isEmpty()) {
            ctx.getMatrices().push();
            ctx.getMatrices().translate(
                    currentX + ARMOR_ICON_SIZE / 2F,
                    baseY + ARMOR_ICON_SIZE / 2F,
                    0);
            ctx.getMatrices().multiply(RotationAxis.POSITIVE_Z.rotationDegrees(360 * (1 - spin)));
            ctx.getMatrices().scale(ARMOR_SCALE * (0.9F + 0.1F * spin),
                    ARMOR_SCALE * (0.9F + 0.1F * spin),
                    1);
            ctx.getMatrices().translate(-8, -8, 0);
            ctx.drawItem(stack, 0, 0);
            ((DrawContextAccessor) ctx).callDrawItemBar(stack, 0, 0);
            ctx.getMatrices().pop();
            currentX += ARMOR_ICON_SIZE;
         }
      }
   }

   // ========== ЭФФЕКТЫ ==========

   private String formatEffectTime(int ticks) {
      int seconds = ticks / 20;
      int minutes = seconds / 60;
      seconds %= 60;
      return String.format(Locale.US, "%d:%02d", minutes, seconds);
   }

   // ========== КЕШИРОВАНИЕ СКИНОВ ==========
   private Identifier getSkinTexture(LivingEntity entity) {
      if (!(entity instanceof PlayerEntity)) {
         return DefaultSkinHelper.getSteve().texture();
      }
      UUID uuid = entity.getUuid();
      if (skinCache.containsKey(uuid)) {
         return skinCache.get(uuid);
      }

      Identifier skin = DefaultSkinHelper.getSteve().texture();
      if (mc.getNetworkHandler() != null) {
         for (PlayerListEntry entry : mc.getNetworkHandler().getPlayerList()) {
            if (entry.getProfile().getId().equals(uuid)) {
               skin = entry.getSkinTextures().texture();
               break;
            }
         }
      }
      skinCache.put(uuid, skin);
      return skin;
   }

   public void setTarget(LivingEntity target) {
      this.target = target;
   }

   // ========== КЛАСС ЧАСТИЦЫ ==========
   private static class Particle {
      float x, y;
      float vx, vy;
      int life;
      int maxLife;
      ColorRGBA color;

      Particle(float x, float y, float vx, float vy, int maxLife, ColorRGBA color) {
         this.x = x;
         this.y = y;
         this.vx = vx;
         this.vy = vy;
         this.maxLife = maxLife;
         this.life = maxLife;
         this.color = color;
      }

      boolean isAlive() {
         return life > 0;
      }

      void update() {
         x += vx;
         y += vy;
         vy += 0.05F;
         life--;
      }
   }
}
 
SS Снизу
Короче вроде норм, но через нейронку

Посмотреть вложение 327492



TargetHudComponent:
Expand Collapse Copy
package fun.mendix.client.hud.elements.component;

import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gl.ShaderProgramKeys;
import net.minecraft.client.gui.screen.ChatScreen;
import net.minecraft.client.network.PlayerListEntry;
import net.minecraft.client.render.*;
import net.minecraft.client.texture.Sprite;
import net.minecraft.client.util.DefaultSkinHelper;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.effect.StatusEffectInstance;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.RotationAxis;
import org.joml.Matrix4f;
import ru.nexusguard.protection.annotations.Native;
import fun.mendix.Mendix;
import fun.mendix.base.animations.base.Animation;
import fun.mendix.base.animations.base.Easing;
import fun.mendix.base.font.Fonts;
import fun.mendix.base.font.MsdfRenderer;
import fun.mendix.base.theme.Theme;
import fun.mendix.client.hud.elements.draggable.DraggableHudElement;
import fun.mendix.client.modules.impl.combat.Aura;
import fun.mendix.client.modules.impl.misc.NameProtect;
import fun.mendix.client.modules.impl.misc.ScoreboardHealth;
import fun.mendix.utility.game.player.PlayerIntersectionUtil;
import fun.mendix.utility.mixin.accessors.DrawContextAccessor;
import fun.mendix.utility.render.display.base.BorderRadius;
import fun.mendix.utility.render.display.base.CustomDrawContext;
import fun.mendix.utility.render.display.base.color.ColorRGBA;
import fun.mendix.utility.render.display.shader.DrawUtil;

import java.util.*;

public class TargetHudComponent extends DraggableHudElement {

   // ========== КОНСТАНТЫ ==========
   private static final float WIDTH = 130F;
   private static final float HEIGHT = 46F;
   private static final float PADDING = 6F;
   private static final float HEAD_SIZE = 28F;
   private static final float BAR_HEIGHT = 4F;
   private static final float BAR_RADIUS = 2F;
   private static final float OUTLINE_WIDTH = 1.8F;
   private static final float ARMOR_ICON_SIZE = 10F;
   private static final float ARMOR_SCALE = 0.65F;
   private static final float EFFECT_ICON_SIZE = 14F;
   private static final long FADE_DURATION = 250L;
   private static final long HEALTH_LAG_DURATION = 700L;
   private static final long ITEM_SPIN_DURATION = 400L;

   // ========== ЧАСТИЦЫ УРОНА ==========
   private static final float SHAKE_INTENSITY = 2.0F;
   private static final int PARTICLE_COUNT_PER_HURT = 4;
   private static final int PARTICLE_LIFETIME = 12;
   private static final float PARTICLE_SPEED = 1.8F;
   private static final Random RANDOM = new Random();

   // ========== АНИМАЦИИ ==========
   private final Animation fadeAnimation = new Animation(FADE_DURATION, Easing.SINE_OUT);
   private final Animation healthAnimation = new Animation(300L, Easing.CUBIC_OUT);
   private final Animation lagHealthAnimation = new Animation(HEALTH_LAG_DURATION, Easing.CUBIC_OUT);
   private final Animation absorptionAnimation = new Animation(250L, Easing.CUBIC_OUT);
   private final Animation itemSpinAnimation = new Animation(ITEM_SPIN_DURATION, Easing.BACK_OUT);
   private final Animation headPopAnimation = new Animation(200L, Easing.BACK_OUT);
   private final Animation hpPulseAnimation = new Animation(600L, Easing.SINE_IN_OUT);

   // ========== СОСТОЯНИЕ ==========
   private LivingEntity target;
   private final Map<UUID, Identifier> skinCache = new HashMap<>();
   private final List<Particle> particles = new ArrayList<>();

   // ========== КОНСТРУКТОР ==========
   public TargetHudComponent(String name, float initialX, float initialY, float windowWidth, float windowHeight,
                             float offsetX, float offsetY, DraggableHudElement.Align align) {
      super(name, initialX, initialY, windowWidth, windowHeight, offsetX, offsetY, align);
   }

   // ========== ОСНОВНОЙ РЕНДЕР ==========
   @Native
   public void render(CustomDrawContext ctx) {
      Aura aura = Aura.INSTANCE;
      LivingEntity newTarget = (mc.currentScreen instanceof ChatScreen) ? mc.player : aura.getTarget();

      updateTargetState(newTarget);
      fadeAnimation.update(target != null);
      headPopAnimation.update(target != null);

      float fade = fadeAnimation.getValue();
      if (fade < 0.01F) return;

      if (target != null) {
         renderTargetHud(ctx, target, fade);
      }
   }

   private void updateTargetState(LivingEntity newTarget) {
      if (newTarget == null) {
         target = null;
         particles.clear();
      } else {
         if (target != newTarget) {
            target = newTarget;
            particles.clear();
            healthAnimation.reset();
            lagHealthAnimation.reset();
            absorptionAnimation.reset();
            itemSpinAnimation.reset();
            itemSpinAnimation.setValue(1.0F);
            headPopAnimation.reset();
            headPopAnimation.setValue(1.0F);

            float maxHealth = target.getMaxHealth();
            float health = ScoreboardHealth.INSTANCE.isEnabled()
                    ? PlayerIntersectionUtil.getHealth(target)
                    : target.getHealth();
            healthAnimation.setValue(health / maxHealth);
            lagHealthAnimation.setValue(health / maxHealth);
            absorptionAnimation.setValue(target.getAbsorptionAmount() / maxHealth);
         }
      }
   }

   // ========== РЕНДЕР ХУДА ==========
   @Native
   private void renderTargetHud(CustomDrawContext ctx, LivingEntity target, float fade) {
      Theme theme = Mendix.getInstance().getThemeManager().getCurrentTheme();
      ColorRGBA themeColor = theme.getColor();
      ColorRGBA themeSecond = theme.getSecondColor();

      float x = this.x;
      float y = this.y;
      float contentX = x + PADDING + HEAD_SIZE + 6F;
      float contentWidth = WIDTH - (PADDING + HEAD_SIZE + 6F) - PADDING;
      float contentY = y + PADDING;

      // --- ТЕНЬ ПОД ХУДОМ ---
      DrawUtil.drawRoundedRect(ctx.getMatrices(), x + 2, y + 2, WIDTH, HEIGHT,
              BorderRadius.all(8F), new ColorRGBA(0, 0, 0, 60 * fade));

      // --- ФОН (СТЕКЛО) ---
      DrawUtil.drawBlur(ctx.getMatrices(), x, y, WIDTH, HEIGHT, 12F,
              BorderRadius.all(8F), new ColorRGBA(80, 80, 80, 160 * fade));
      DrawUtil.drawRoundedRect(ctx.getMatrices(), x, y, WIDTH, HEIGHT,
              BorderRadius.all(8F), new ColorRGBA(10, 10, 10, 220 * fade));

      // --- ОБВОДКА — ЦВЕТ ТЕМЫ (ХАРАКТЕРНЫЙ ТЕМЕ) ---
      ColorRGBA borderColor = themeColor.mix(themeSecond, 0.5F).withAlpha(255 * fade);
      DrawUtil.drawRoundedBorder(ctx.getMatrices(), x, y, WIDTH, HEIGHT, OUTLINE_WIDTH,
              BorderRadius.all(8F), borderColor);

      // --- АВАТАРКА ---
      Identifier skin = getSkinTexture(target);
      float headSize = HEAD_SIZE * (0.9F + 0.1F * headPopAnimation.getValue());
      float headX = x + PADDING + (HEAD_SIZE - headSize) / 2;
      float headY = y + PADDING + (HEAD_SIZE - headSize) / 2;

      DrawUtil.drawRoundedRect(ctx.getMatrices(), headX - 2, headY - 2, headSize + 4, headSize + 4,
              BorderRadius.all(8F), themeColor.withAlpha(80 * fade));

      boolean isHurt = target.hurtTime > 0;
      if (isHurt) {
         ctx.getMatrices().push();
         float shakeX = (RANDOM.nextFloat() - 0.5F) * SHAKE_INTENSITY;
         float shakeY = (RANDOM.nextFloat() - 0.5F) * SHAKE_INTENSITY;
         ctx.getMatrices().translate(shakeX, shakeY, 0);
         spawnDamageParticles(headX + headSize / 2, headY + headSize / 2, themeColor);
      }

      DrawUtil.drawPlayerHeadWithRoundedShader(ctx.getMatrices(), skin,
              headX, headY, headSize,
              BorderRadius.all(6F), ColorRGBA.WHITE.withAlpha(255 * fade));

      if (isHurt) {
         ctx.getMatrices().pop();
      }

      updateParticles();
      renderParticles(ctx, ctx.getMatrices(), fade);

      // --- ИМЯ ЦЕЛИ ---
      String name = (target == mc.player && NameProtect.INSTANCE.isEnabled())
              ? NameProtect.getCustomName()
              : target.getNameForScoreboard();

      MsdfRenderer.renderText(Fonts.BOLD, name, 9F,
              new ColorRGBA(0, 0, 0, 100 * fade).getRGB(),
              ctx.getMatrices().peek().getPositionMatrix(),
              contentX + 1, contentY + 1F, 0F, true, 0.7F, 1F, contentWidth);
      MsdfRenderer.renderText(Fonts.BOLD, name, 9F,
              ColorRGBA.WHITE.withAlpha(255 * fade).getRGB(),
              ctx.getMatrices().peek().getPositionMatrix(),
              contentX, contentY, 0F, true, 0.7F, 1F, contentWidth);

      // --- РАССТОЯНИЕ ---
      if (mc.player != null) {
         float dist = mc.player.distanceTo(target);
         String distText = String.format(Locale.US, "%.1f м", dist);
         MsdfRenderer.renderText(Fonts.REGULAR, distText, 7F,
                 new ColorRGBA(180, 180, 180, 200 * fade).getRGB(),
                 ctx.getMatrices().peek().getPositionMatrix(),
                 contentX, contentY + 10F, 0F, true, 0.7F, 1F, contentWidth);
      }

      // --- ПОЛОСКА ЗДОРОВЬЯ ---
      float maxHealth = target.getMaxHealth();
      float health = ScoreboardHealth.INSTANCE.isEnabled()
              ? PlayerIntersectionUtil.getHealth(target)
              : target.getHealth();
      float healthPercentCurrent = health / maxHealth;
      float absorptionPercent = target.getAbsorptionAmount() / maxHealth;

      healthAnimation.update(healthPercentCurrent);
      absorptionAnimation.update(absorptionPercent);

      if (lagHealthAnimation.getValue() > healthPercentCurrent) {
         lagHealthAnimation.update(healthPercentCurrent);
      } else {
         lagHealthAnimation.setValue(healthPercentCurrent);
      }

      float barY = y + HEIGHT - PADDING - BAR_HEIGHT;

      DrawUtil.drawRoundedRect(ctx.getMatrices(), contentX, barY, contentWidth, BAR_HEIGHT,
              BorderRadius.all(BAR_RADIUS), new ColorRGBA(20, 20, 20, 255 * fade));

      float lagWidth = contentWidth * lagHealthAnimation.getValue();
      if (lagWidth > 0) {
         DrawUtil.drawRoundedRect(ctx.getMatrices(), contentX, barY, lagWidth, BAR_HEIGHT,
                 BorderRadius.all(BAR_RADIUS), new ColorRGBA(150, 50, 50, 150 * fade));
      }

      float healthWidth = contentWidth * healthAnimation.getValue();
      if (healthWidth > 0) {
         ColorRGBA healthColor1 = interpolateColorGradient(healthPercentCurrent);
         ColorRGBA healthColor2 = healthColor1.darker(0.8F);
         DrawUtil.drawRoundedRect(ctx.getMatrices(), contentX, barY, healthWidth, BAR_HEIGHT,
                 BorderRadius.all(BAR_RADIUS),
                 healthColor1.withAlpha(255 * fade), healthColor1.withAlpha(255 * fade),
                 healthColor2.withAlpha(255 * fade), healthColor2.withAlpha(255 * fade));
      }

      hpPulseAnimation.update(healthPercentCurrent < 0.2F);
      float pulseGlow = hpPulseAnimation.getValue() * 0.3F;
      if (healthPercentCurrent < 0.2F) {
         DrawUtil.drawRoundedRect(ctx.getMatrices(),
                 contentX - 1, barY - 1, healthWidth + 2, BAR_HEIGHT + 2,
                 BorderRadius.all(BAR_RADIUS + 1),
                 new ColorRGBA(255, 50, 50, (int)(80 * fade * pulseGlow)));
      }

      float absorptionWidth = contentWidth * absorptionAnimation.getValue();
      if (absorptionWidth > 0) {
         float sparkle = (MathHelper.sin(mc.player.age * 0.3F) * 0.5F + 0.5F) * 0.5F + 0.5F;
         DrawUtil.drawRoundedRect(ctx.getMatrices(),
                 contentX, barY - 1.5F, absorptionWidth, 2.5F,
                 BorderRadius.all(1.5F),
                 new ColorRGBA(255, 215, 0, (int)(200 * fade * sparkle)));
      }

      // --- ТЕКСТ HP — СПРАВА НАД ПОЛОСКОЙ ---
      String hpText = String.format(Locale.US, "%.0f", health);
      float hpFontSize = 6F;
      float hpWidth = Fonts.REGULAR.getFont(hpFontSize).width(hpText);
      float hpX = contentX + contentWidth - hpWidth - 2F;
      float hpY = barY - 8F;

      ctx.drawText(Fonts.REGULAR.getFont(hpFontSize), hpText,
              hpX + 1, hpY + 1,
              new ColorRGBA(0, 0, 0, 100 * fade));
      ctx.drawText(Fonts.REGULAR.getFont(hpFontSize), hpText,
              hpX, hpY,
              ColorRGBA.WHITE.withAlpha(230 * fade));

      // --- БРОНЯ ---
      if (target instanceof PlayerEntity) {
         renderArmorAndItems(ctx, (PlayerEntity) target, x, y + HEIGHT + 4F, WIDTH, fade);
      }

      this.width = WIDTH;
      this.height = HEIGHT;
   }

   // ========== ЦВЕТ ЗДОРОВЬЯ ==========
   private ColorRGBA interpolateColorGradient(float percent) {
      if (percent > 0.8F) return new ColorRGBA(50, 255, 50);
      if (percent > 0.5F) return new ColorRGBA(255, 255, 50);
      if (percent > 0.2F) return new ColorRGBA(255, 150, 50);
      return new ColorRGBA(255, 50, 50);
   }

   // ========== ЧАСТИЦЫ УРОНА ==========
   private void spawnDamageParticles(float centerX, float centerY, ColorRGBA themeColor) {
      ColorRGBA baseColor = themeColor.mix(ColorRGBA.RED, 0.5F);

      for (int i = 0; i < PARTICLE_COUNT_PER_HURT; i++) {
         float angle = RANDOM.nextFloat() * (float) Math.PI * 2;
         float speed = PARTICLE_SPEED * (0.7F + RANDOM.nextFloat() * 0.6F);
         float vx = (float) Math.cos(angle) * speed;
         float vy = (float) Math.sin(angle) * speed - 0.5F;

         int lifetime = PARTICLE_LIFETIME + RANDOM.nextInt(6) - 3;
         float variation = 0.8F + RANDOM.nextFloat() * 0.4F;

         int r = (int) MathHelper.clamp(baseColor.getRed() * variation, 0, 255);
         int g = (int) MathHelper.clamp(baseColor.getGreen() * variation, 0, 255);
         int b = (int) MathHelper.clamp(baseColor.getBlue() * variation, 0, 255);
         int a = baseColor.getAlpha();

         ColorRGBA particleColor = new ColorRGBA(r, g, b, a);
         particles.add(new Particle(centerX, centerY, vx, vy, lifetime, particleColor));
      }
   }

   private void updateParticles() {
      particles.removeIf(p -> {
         p.update();
         return !p.isAlive();
      });
   }

   private void renderParticles(CustomDrawContext ctx, MatrixStack matrices, float fade) {
      if (particles.isEmpty()) return;

      RenderSystem.enableBlend();
      RenderSystem.defaultBlendFunc();
      RenderSystem.disableDepthTest();
      RenderSystem.depthMask(false);
      RenderSystem.setShader(ShaderProgramKeys.POSITION_COLOR);

      Matrix4f matrix = matrices.peek().getPositionMatrix();
      BufferBuilder buffer = Tessellator.getInstance().begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR);

      for (Particle p : particles) {
         float alpha = (float) p.life / p.maxLife * fade;
         int a = (int) (alpha * 255);
         int color = p.color.withAlpha(a).getRGB();

         float size = 1.5F + (1.0F - (float) p.life / p.maxLife) * 1.0F;
         float x1 = p.x - size;
         float y1 = p.y - size;
         float x2 = p.x + size;
         float y2 = p.y + size;

         int r = (color >> 16) & 0xFF;
         int g = (color >> 8) & 0xFF;
         int b = color & 0xFF;
         int a2 = (color >> 24) & 0xFF;

         buffer.vertex(matrix, x1, y2, 0).color(r, g, b, a2);
         buffer.vertex(matrix, x2, y2, 0).color(r, g, b, a2);
         buffer.vertex(matrix, x2, y1, 0).color(r, g, b, a2);
         buffer.vertex(matrix, x1, y1, 0).color(r, g, b, a2);
      }

      BufferRenderer.drawWithGlobalProgram(buffer.end());

      RenderSystem.enableDepthTest();
      RenderSystem.depthMask(true);
      RenderSystem.disableBlend();
   }

   // ========== БРОНЯ И ПРЕДМЕТЫ ==========
   private void renderArmorAndItems(CustomDrawContext ctx, PlayerEntity player, float baseX, float baseY, float hudWidth, float fade) {
      List<ItemStack> armor = player.getInventory().armor;
      ItemStack[] items = {
              player.getMainHandStack(),
              player.getOffHandStack(),
              armor.get(3),
              armor.get(2),
              armor.get(1),
              armor.get(0)
      };

      int count = 0;
      for (ItemStack stack : items) if (!stack.isEmpty()) count++;
      if (count == 0) return;

      float totalWidth = count * ARMOR_ICON_SIZE;
      float startX = baseX + (hudWidth - totalWidth) / 2F;
      float currentX = startX;

      DrawUtil.drawRoundedRect(ctx.getMatrices(),
              startX - 3, baseY - 2,
              totalWidth + 6, ARMOR_ICON_SIZE + 4,
              BorderRadius.all(4F),
              new ColorRGBA(20, 20, 20, 150 * fade));

      itemSpinAnimation.update(true);
      float spin = itemSpinAnimation.getValue();

      for (ItemStack stack : items) {
         if (!stack.isEmpty()) {
            ctx.getMatrices().push();
            ctx.getMatrices().translate(
                    currentX + ARMOR_ICON_SIZE / 2F,
                    baseY + ARMOR_ICON_SIZE / 2F,
                    0);
            ctx.getMatrices().multiply(RotationAxis.POSITIVE_Z.rotationDegrees(360 * (1 - spin)));
            ctx.getMatrices().scale(ARMOR_SCALE * (0.9F + 0.1F * spin),
                    ARMOR_SCALE * (0.9F + 0.1F * spin),
                    1);
            ctx.getMatrices().translate(-8, -8, 0);
            ctx.drawItem(stack, 0, 0);
            ((DrawContextAccessor) ctx).callDrawItemBar(stack, 0, 0);
            ctx.getMatrices().pop();
            currentX += ARMOR_ICON_SIZE;
         }
      }
   }

   // ========== ЭФФЕКТЫ ==========

   private String formatEffectTime(int ticks) {
      int seconds = ticks / 20;
      int minutes = seconds / 60;
      seconds %= 60;
      return String.format(Locale.US, "%d:%02d", minutes, seconds);
   }

   // ========== КЕШИРОВАНИЕ СКИНОВ ==========
   private Identifier getSkinTexture(LivingEntity entity) {
      if (!(entity instanceof PlayerEntity)) {
         return DefaultSkinHelper.getSteve().texture();
      }
      UUID uuid = entity.getUuid();
      if (skinCache.containsKey(uuid)) {
         return skinCache.get(uuid);
      }

      Identifier skin = DefaultSkinHelper.getSteve().texture();
      if (mc.getNetworkHandler() != null) {
         for (PlayerListEntry entry : mc.getNetworkHandler().getPlayerList()) {
            if (entry.getProfile().getId().equals(uuid)) {
               skin = entry.getSkinTextures().texture();
               break;
            }
         }
      }
      skinCache.put(uuid, skin);
      return skin;
   }

   public void setTarget(LivingEntity target) {
      this.target = target;
   }

   // ========== КЛАСС ЧАСТИЦЫ ==========
   private static class Particle {
      float x, y;
      float vx, vy;
      int life;
      int maxLife;
      ColorRGBA color;

      Particle(float x, float y, float vx, float vy, int maxLife, ColorRGBA color) {
         this.x = x;
         this.y = y;
         this.vx = vx;
         this.vy = vy;
         this.maxLife = maxLife;
         this.life = maxLife;
         this.color = color;
      }

      boolean isAlive() {
         return life > 0;
      }

      void update() {
         x += vx;
         y += vy;
         vy += 0.05F;
         life--;
      }
   }
}
пиздец братан
 
SS Снизу
Короче вроде норм, но через нейронку

Посмотреть вложение 327492



TargetHudComponent:
Expand Collapse Copy
package fun.mendix.client.hud.elements.component;

import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gl.ShaderProgramKeys;
import net.minecraft.client.gui.screen.ChatScreen;
import net.minecraft.client.network.PlayerListEntry;
import net.minecraft.client.render.*;
import net.minecraft.client.texture.Sprite;
import net.minecraft.client.util.DefaultSkinHelper;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.effect.StatusEffectInstance;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.RotationAxis;
import org.joml.Matrix4f;
import ru.nexusguard.protection.annotations.Native;
import fun.mendix.Mendix;
import fun.mendix.base.animations.base.Animation;
import fun.mendix.base.animations.base.Easing;
import fun.mendix.base.font.Fonts;
import fun.mendix.base.font.MsdfRenderer;
import fun.mendix.base.theme.Theme;
import fun.mendix.client.hud.elements.draggable.DraggableHudElement;
import fun.mendix.client.modules.impl.combat.Aura;
import fun.mendix.client.modules.impl.misc.NameProtect;
import fun.mendix.client.modules.impl.misc.ScoreboardHealth;
import fun.mendix.utility.game.player.PlayerIntersectionUtil;
import fun.mendix.utility.mixin.accessors.DrawContextAccessor;
import fun.mendix.utility.render.display.base.BorderRadius;
import fun.mendix.utility.render.display.base.CustomDrawContext;
import fun.mendix.utility.render.display.base.color.ColorRGBA;
import fun.mendix.utility.render.display.shader.DrawUtil;

import java.util.*;

public class TargetHudComponent extends DraggableHudElement {

   // ========== КОНСТАНТЫ ==========
   private static final float WIDTH = 130F;
   private static final float HEIGHT = 46F;
   private static final float PADDING = 6F;
   private static final float HEAD_SIZE = 28F;
   private static final float BAR_HEIGHT = 4F;
   private static final float BAR_RADIUS = 2F;
   private static final float OUTLINE_WIDTH = 1.8F;
   private static final float ARMOR_ICON_SIZE = 10F;
   private static final float ARMOR_SCALE = 0.65F;
   private static final float EFFECT_ICON_SIZE = 14F;
   private static final long FADE_DURATION = 250L;
   private static final long HEALTH_LAG_DURATION = 700L;
   private static final long ITEM_SPIN_DURATION = 400L;

   // ========== ЧАСТИЦЫ УРОНА ==========
   private static final float SHAKE_INTENSITY = 2.0F;
   private static final int PARTICLE_COUNT_PER_HURT = 4;
   private static final int PARTICLE_LIFETIME = 12;
   private static final float PARTICLE_SPEED = 1.8F;
   private static final Random RANDOM = new Random();

   // ========== АНИМАЦИИ ==========
   private final Animation fadeAnimation = new Animation(FADE_DURATION, Easing.SINE_OUT);
   private final Animation healthAnimation = new Animation(300L, Easing.CUBIC_OUT);
   private final Animation lagHealthAnimation = new Animation(HEALTH_LAG_DURATION, Easing.CUBIC_OUT);
   private final Animation absorptionAnimation = new Animation(250L, Easing.CUBIC_OUT);
   private final Animation itemSpinAnimation = new Animation(ITEM_SPIN_DURATION, Easing.BACK_OUT);
   private final Animation headPopAnimation = new Animation(200L, Easing.BACK_OUT);
   private final Animation hpPulseAnimation = new Animation(600L, Easing.SINE_IN_OUT);

   // ========== СОСТОЯНИЕ ==========
   private LivingEntity target;
   private final Map<UUID, Identifier> skinCache = new HashMap<>();
   private final List<Particle> particles = new ArrayList<>();

   // ========== КОНСТРУКТОР ==========
   public TargetHudComponent(String name, float initialX, float initialY, float windowWidth, float windowHeight,
                             float offsetX, float offsetY, DraggableHudElement.Align align) {
      super(name, initialX, initialY, windowWidth, windowHeight, offsetX, offsetY, align);
   }

   // ========== ОСНОВНОЙ РЕНДЕР ==========
   @Native
   public void render(CustomDrawContext ctx) {
      Aura aura = Aura.INSTANCE;
      LivingEntity newTarget = (mc.currentScreen instanceof ChatScreen) ? mc.player : aura.getTarget();

      updateTargetState(newTarget);
      fadeAnimation.update(target != null);
      headPopAnimation.update(target != null);

      float fade = fadeAnimation.getValue();
      if (fade < 0.01F) return;

      if (target != null) {
         renderTargetHud(ctx, target, fade);
      }
   }

   private void updateTargetState(LivingEntity newTarget) {
      if (newTarget == null) {
         target = null;
         particles.clear();
      } else {
         if (target != newTarget) {
            target = newTarget;
            particles.clear();
            healthAnimation.reset();
            lagHealthAnimation.reset();
            absorptionAnimation.reset();
            itemSpinAnimation.reset();
            itemSpinAnimation.setValue(1.0F);
            headPopAnimation.reset();
            headPopAnimation.setValue(1.0F);

            float maxHealth = target.getMaxHealth();
            float health = ScoreboardHealth.INSTANCE.isEnabled()
                    ? PlayerIntersectionUtil.getHealth(target)
                    : target.getHealth();
            healthAnimation.setValue(health / maxHealth);
            lagHealthAnimation.setValue(health / maxHealth);
            absorptionAnimation.setValue(target.getAbsorptionAmount() / maxHealth);
         }
      }
   }

   // ========== РЕНДЕР ХУДА ==========
   @Native
   private void renderTargetHud(CustomDrawContext ctx, LivingEntity target, float fade) {
      Theme theme = Mendix.getInstance().getThemeManager().getCurrentTheme();
      ColorRGBA themeColor = theme.getColor();
      ColorRGBA themeSecond = theme.getSecondColor();

      float x = this.x;
      float y = this.y;
      float contentX = x + PADDING + HEAD_SIZE + 6F;
      float contentWidth = WIDTH - (PADDING + HEAD_SIZE + 6F) - PADDING;
      float contentY = y + PADDING;

      // --- ТЕНЬ ПОД ХУДОМ ---
      DrawUtil.drawRoundedRect(ctx.getMatrices(), x + 2, y + 2, WIDTH, HEIGHT,
              BorderRadius.all(8F), new ColorRGBA(0, 0, 0, 60 * fade));

      // --- ФОН (СТЕКЛО) ---
      DrawUtil.drawBlur(ctx.getMatrices(), x, y, WIDTH, HEIGHT, 12F,
              BorderRadius.all(8F), new ColorRGBA(80, 80, 80, 160 * fade));
      DrawUtil.drawRoundedRect(ctx.getMatrices(), x, y, WIDTH, HEIGHT,
              BorderRadius.all(8F), new ColorRGBA(10, 10, 10, 220 * fade));

      // --- ОБВОДКА — ЦВЕТ ТЕМЫ (ХАРАКТЕРНЫЙ ТЕМЕ) ---
      ColorRGBA borderColor = themeColor.mix(themeSecond, 0.5F).withAlpha(255 * fade);
      DrawUtil.drawRoundedBorder(ctx.getMatrices(), x, y, WIDTH, HEIGHT, OUTLINE_WIDTH,
              BorderRadius.all(8F), borderColor);

      // --- АВАТАРКА ---
      Identifier skin = getSkinTexture(target);
      float headSize = HEAD_SIZE * (0.9F + 0.1F * headPopAnimation.getValue());
      float headX = x + PADDING + (HEAD_SIZE - headSize) / 2;
      float headY = y + PADDING + (HEAD_SIZE - headSize) / 2;

      DrawUtil.drawRoundedRect(ctx.getMatrices(), headX - 2, headY - 2, headSize + 4, headSize + 4,
              BorderRadius.all(8F), themeColor.withAlpha(80 * fade));

      boolean isHurt = target.hurtTime > 0;
      if (isHurt) {
         ctx.getMatrices().push();
         float shakeX = (RANDOM.nextFloat() - 0.5F) * SHAKE_INTENSITY;
         float shakeY = (RANDOM.nextFloat() - 0.5F) * SHAKE_INTENSITY;
         ctx.getMatrices().translate(shakeX, shakeY, 0);
         spawnDamageParticles(headX + headSize / 2, headY + headSize / 2, themeColor);
      }

      DrawUtil.drawPlayerHeadWithRoundedShader(ctx.getMatrices(), skin,
              headX, headY, headSize,
              BorderRadius.all(6F), ColorRGBA.WHITE.withAlpha(255 * fade));

      if (isHurt) {
         ctx.getMatrices().pop();
      }

      updateParticles();
      renderParticles(ctx, ctx.getMatrices(), fade);

      // --- ИМЯ ЦЕЛИ ---
      String name = (target == mc.player && NameProtect.INSTANCE.isEnabled())
              ? NameProtect.getCustomName()
              : target.getNameForScoreboard();

      MsdfRenderer.renderText(Fonts.BOLD, name, 9F,
              new ColorRGBA(0, 0, 0, 100 * fade).getRGB(),
              ctx.getMatrices().peek().getPositionMatrix(),
              contentX + 1, contentY + 1F, 0F, true, 0.7F, 1F, contentWidth);
      MsdfRenderer.renderText(Fonts.BOLD, name, 9F,
              ColorRGBA.WHITE.withAlpha(255 * fade).getRGB(),
              ctx.getMatrices().peek().getPositionMatrix(),
              contentX, contentY, 0F, true, 0.7F, 1F, contentWidth);

      // --- РАССТОЯНИЕ ---
      if (mc.player != null) {
         float dist = mc.player.distanceTo(target);
         String distText = String.format(Locale.US, "%.1f м", dist);
         MsdfRenderer.renderText(Fonts.REGULAR, distText, 7F,
                 new ColorRGBA(180, 180, 180, 200 * fade).getRGB(),
                 ctx.getMatrices().peek().getPositionMatrix(),
                 contentX, contentY + 10F, 0F, true, 0.7F, 1F, contentWidth);
      }

      // --- ПОЛОСКА ЗДОРОВЬЯ ---
      float maxHealth = target.getMaxHealth();
      float health = ScoreboardHealth.INSTANCE.isEnabled()
              ? PlayerIntersectionUtil.getHealth(target)
              : target.getHealth();
      float healthPercentCurrent = health / maxHealth;
      float absorptionPercent = target.getAbsorptionAmount() / maxHealth;

      healthAnimation.update(healthPercentCurrent);
      absorptionAnimation.update(absorptionPercent);

      if (lagHealthAnimation.getValue() > healthPercentCurrent) {
         lagHealthAnimation.update(healthPercentCurrent);
      } else {
         lagHealthAnimation.setValue(healthPercentCurrent);
      }

      float barY = y + HEIGHT - PADDING - BAR_HEIGHT;

      DrawUtil.drawRoundedRect(ctx.getMatrices(), contentX, barY, contentWidth, BAR_HEIGHT,
              BorderRadius.all(BAR_RADIUS), new ColorRGBA(20, 20, 20, 255 * fade));

      float lagWidth = contentWidth * lagHealthAnimation.getValue();
      if (lagWidth > 0) {
         DrawUtil.drawRoundedRect(ctx.getMatrices(), contentX, barY, lagWidth, BAR_HEIGHT,
                 BorderRadius.all(BAR_RADIUS), new ColorRGBA(150, 50, 50, 150 * fade));
      }

      float healthWidth = contentWidth * healthAnimation.getValue();
      if (healthWidth > 0) {
         ColorRGBA healthColor1 = interpolateColorGradient(healthPercentCurrent);
         ColorRGBA healthColor2 = healthColor1.darker(0.8F);
         DrawUtil.drawRoundedRect(ctx.getMatrices(), contentX, barY, healthWidth, BAR_HEIGHT,
                 BorderRadius.all(BAR_RADIUS),
                 healthColor1.withAlpha(255 * fade), healthColor1.withAlpha(255 * fade),
                 healthColor2.withAlpha(255 * fade), healthColor2.withAlpha(255 * fade));
      }

      hpPulseAnimation.update(healthPercentCurrent < 0.2F);
      float pulseGlow = hpPulseAnimation.getValue() * 0.3F;
      if (healthPercentCurrent < 0.2F) {
         DrawUtil.drawRoundedRect(ctx.getMatrices(),
                 contentX - 1, barY - 1, healthWidth + 2, BAR_HEIGHT + 2,
                 BorderRadius.all(BAR_RADIUS + 1),
                 new ColorRGBA(255, 50, 50, (int)(80 * fade * pulseGlow)));
      }

      float absorptionWidth = contentWidth * absorptionAnimation.getValue();
      if (absorptionWidth > 0) {
         float sparkle = (MathHelper.sin(mc.player.age * 0.3F) * 0.5F + 0.5F) * 0.5F + 0.5F;
         DrawUtil.drawRoundedRect(ctx.getMatrices(),
                 contentX, barY - 1.5F, absorptionWidth, 2.5F,
                 BorderRadius.all(1.5F),
                 new ColorRGBA(255, 215, 0, (int)(200 * fade * sparkle)));
      }

      // --- ТЕКСТ HP — СПРАВА НАД ПОЛОСКОЙ ---
      String hpText = String.format(Locale.US, "%.0f", health);
      float hpFontSize = 6F;
      float hpWidth = Fonts.REGULAR.getFont(hpFontSize).width(hpText);
      float hpX = contentX + contentWidth - hpWidth - 2F;
      float hpY = barY - 8F;

      ctx.drawText(Fonts.REGULAR.getFont(hpFontSize), hpText,
              hpX + 1, hpY + 1,
              new ColorRGBA(0, 0, 0, 100 * fade));
      ctx.drawText(Fonts.REGULAR.getFont(hpFontSize), hpText,
              hpX, hpY,
              ColorRGBA.WHITE.withAlpha(230 * fade));

      // --- БРОНЯ ---
      if (target instanceof PlayerEntity) {
         renderArmorAndItems(ctx, (PlayerEntity) target, x, y + HEIGHT + 4F, WIDTH, fade);
      }

      this.width = WIDTH;
      this.height = HEIGHT;
   }

   // ========== ЦВЕТ ЗДОРОВЬЯ ==========
   private ColorRGBA interpolateColorGradient(float percent) {
      if (percent > 0.8F) return new ColorRGBA(50, 255, 50);
      if (percent > 0.5F) return new ColorRGBA(255, 255, 50);
      if (percent > 0.2F) return new ColorRGBA(255, 150, 50);
      return new ColorRGBA(255, 50, 50);
   }

   // ========== ЧАСТИЦЫ УРОНА ==========
   private void spawnDamageParticles(float centerX, float centerY, ColorRGBA themeColor) {
      ColorRGBA baseColor = themeColor.mix(ColorRGBA.RED, 0.5F);

      for (int i = 0; i < PARTICLE_COUNT_PER_HURT; i++) {
         float angle = RANDOM.nextFloat() * (float) Math.PI * 2;
         float speed = PARTICLE_SPEED * (0.7F + RANDOM.nextFloat() * 0.6F);
         float vx = (float) Math.cos(angle) * speed;
         float vy = (float) Math.sin(angle) * speed - 0.5F;

         int lifetime = PARTICLE_LIFETIME + RANDOM.nextInt(6) - 3;
         float variation = 0.8F + RANDOM.nextFloat() * 0.4F;

         int r = (int) MathHelper.clamp(baseColor.getRed() * variation, 0, 255);
         int g = (int) MathHelper.clamp(baseColor.getGreen() * variation, 0, 255);
         int b = (int) MathHelper.clamp(baseColor.getBlue() * variation, 0, 255);
         int a = baseColor.getAlpha();

         ColorRGBA particleColor = new ColorRGBA(r, g, b, a);
         particles.add(new Particle(centerX, centerY, vx, vy, lifetime, particleColor));
      }
   }

   private void updateParticles() {
      particles.removeIf(p -> {
         p.update();
         return !p.isAlive();
      });
   }

   private void renderParticles(CustomDrawContext ctx, MatrixStack matrices, float fade) {
      if (particles.isEmpty()) return;

      RenderSystem.enableBlend();
      RenderSystem.defaultBlendFunc();
      RenderSystem.disableDepthTest();
      RenderSystem.depthMask(false);
      RenderSystem.setShader(ShaderProgramKeys.POSITION_COLOR);

      Matrix4f matrix = matrices.peek().getPositionMatrix();
      BufferBuilder buffer = Tessellator.getInstance().begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR);

      for (Particle p : particles) {
         float alpha = (float) p.life / p.maxLife * fade;
         int a = (int) (alpha * 255);
         int color = p.color.withAlpha(a).getRGB();

         float size = 1.5F + (1.0F - (float) p.life / p.maxLife) * 1.0F;
         float x1 = p.x - size;
         float y1 = p.y - size;
         float x2 = p.x + size;
         float y2 = p.y + size;

         int r = (color >> 16) & 0xFF;
         int g = (color >> 8) & 0xFF;
         int b = color & 0xFF;
         int a2 = (color >> 24) & 0xFF;

         buffer.vertex(matrix, x1, y2, 0).color(r, g, b, a2);
         buffer.vertex(matrix, x2, y2, 0).color(r, g, b, a2);
         buffer.vertex(matrix, x2, y1, 0).color(r, g, b, a2);
         buffer.vertex(matrix, x1, y1, 0).color(r, g, b, a2);
      }

      BufferRenderer.drawWithGlobalProgram(buffer.end());

      RenderSystem.enableDepthTest();
      RenderSystem.depthMask(true);
      RenderSystem.disableBlend();
   }

   // ========== БРОНЯ И ПРЕДМЕТЫ ==========
   private void renderArmorAndItems(CustomDrawContext ctx, PlayerEntity player, float baseX, float baseY, float hudWidth, float fade) {
      List<ItemStack> armor = player.getInventory().armor;
      ItemStack[] items = {
              player.getMainHandStack(),
              player.getOffHandStack(),
              armor.get(3),
              armor.get(2),
              armor.get(1),
              armor.get(0)
      };

      int count = 0;
      for (ItemStack stack : items) if (!stack.isEmpty()) count++;
      if (count == 0) return;

      float totalWidth = count * ARMOR_ICON_SIZE;
      float startX = baseX + (hudWidth - totalWidth) / 2F;
      float currentX = startX;

      DrawUtil.drawRoundedRect(ctx.getMatrices(),
              startX - 3, baseY - 2,
              totalWidth + 6, ARMOR_ICON_SIZE + 4,
              BorderRadius.all(4F),
              new ColorRGBA(20, 20, 20, 150 * fade));

      itemSpinAnimation.update(true);
      float spin = itemSpinAnimation.getValue();

      for (ItemStack stack : items) {
         if (!stack.isEmpty()) {
            ctx.getMatrices().push();
            ctx.getMatrices().translate(
                    currentX + ARMOR_ICON_SIZE / 2F,
                    baseY + ARMOR_ICON_SIZE / 2F,
                    0);
            ctx.getMatrices().multiply(RotationAxis.POSITIVE_Z.rotationDegrees(360 * (1 - spin)));
            ctx.getMatrices().scale(ARMOR_SCALE * (0.9F + 0.1F * spin),
                    ARMOR_SCALE * (0.9F + 0.1F * spin),
                    1);
            ctx.getMatrices().translate(-8, -8, 0);
            ctx.drawItem(stack, 0, 0);
            ((DrawContextAccessor) ctx).callDrawItemBar(stack, 0, 0);
            ctx.getMatrices().pop();
            currentX += ARMOR_ICON_SIZE;
         }
      }
   }

   // ========== ЭФФЕКТЫ ==========

   private String formatEffectTime(int ticks) {
      int seconds = ticks / 20;
      int minutes = seconds / 60;
      seconds %= 60;
      return String.format(Locale.US, "%d:%02d", minutes, seconds);
   }

   // ========== КЕШИРОВАНИЕ СКИНОВ ==========
   private Identifier getSkinTexture(LivingEntity entity) {
      if (!(entity instanceof PlayerEntity)) {
         return DefaultSkinHelper.getSteve().texture();
      }
      UUID uuid = entity.getUuid();
      if (skinCache.containsKey(uuid)) {
         return skinCache.get(uuid);
      }

      Identifier skin = DefaultSkinHelper.getSteve().texture();
      if (mc.getNetworkHandler() != null) {
         for (PlayerListEntry entry : mc.getNetworkHandler().getPlayerList()) {
            if (entry.getProfile().getId().equals(uuid)) {
               skin = entry.getSkinTextures().texture();
               break;
            }
         }
      }
      skinCache.put(uuid, skin);
      return skin;
   }

   public void setTarget(LivingEntity target) {
      this.target = target;
   }

   // ========== КЛАСС ЧАСТИЦЫ ==========
   private static class Particle {
      float x, y;
      float vx, vy;
      int life;
      int maxLife;
      ColorRGBA color;

      Particle(float x, float y, float vx, float vy, int maxLife, ColorRGBA color) {
         this.x = x;
         this.y = y;
         this.vx = vx;
         this.vy = vy;
         this.maxLife = maxLife;
         this.life = maxLife;
         this.color = color;
      }

      boolean isAlive() {
         return life > 0;
      }

      void update() {
         x += vx;
         y += vy;
         vy += 0.05F;
         life--;
      }
   }
}
ну так се у тебя день рождение будет, фулл ИИ так ещё и сам по се кривой

upd: др у другого типа с форума так что перепутал но всё равно криво
 
Последнее редактирование:
SS Снизу
Короче вроде норм, но через нейронку

Посмотреть вложение 327492



TargetHudComponent:
Expand Collapse Copy
package fun.mendix.client.hud.elements.component;

import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gl.ShaderProgramKeys;
import net.minecraft.client.gui.screen.ChatScreen;
import net.minecraft.client.network.PlayerListEntry;
import net.minecraft.client.render.*;
import net.minecraft.client.texture.Sprite;
import net.minecraft.client.util.DefaultSkinHelper;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.effect.StatusEffectInstance;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.RotationAxis;
import org.joml.Matrix4f;
import ru.nexusguard.protection.annotations.Native;
import fun.mendix.Mendix;
import fun.mendix.base.animations.base.Animation;
import fun.mendix.base.animations.base.Easing;
import fun.mendix.base.font.Fonts;
import fun.mendix.base.font.MsdfRenderer;
import fun.mendix.base.theme.Theme;
import fun.mendix.client.hud.elements.draggable.DraggableHudElement;
import fun.mendix.client.modules.impl.combat.Aura;
import fun.mendix.client.modules.impl.misc.NameProtect;
import fun.mendix.client.modules.impl.misc.ScoreboardHealth;
import fun.mendix.utility.game.player.PlayerIntersectionUtil;
import fun.mendix.utility.mixin.accessors.DrawContextAccessor;
import fun.mendix.utility.render.display.base.BorderRadius;
import fun.mendix.utility.render.display.base.CustomDrawContext;
import fun.mendix.utility.render.display.base.color.ColorRGBA;
import fun.mendix.utility.render.display.shader.DrawUtil;

import java.util.*;

public class TargetHudComponent extends DraggableHudElement {

   // ========== КОНСТАНТЫ ==========
   private static final float WIDTH = 130F;
   private static final float HEIGHT = 46F;
   private static final float PADDING = 6F;
   private static final float HEAD_SIZE = 28F;
   private static final float BAR_HEIGHT = 4F;
   private static final float BAR_RADIUS = 2F;
   private static final float OUTLINE_WIDTH = 1.8F;
   private static final float ARMOR_ICON_SIZE = 10F;
   private static final float ARMOR_SCALE = 0.65F;
   private static final float EFFECT_ICON_SIZE = 14F;
   private static final long FADE_DURATION = 250L;
   private static final long HEALTH_LAG_DURATION = 700L;
   private static final long ITEM_SPIN_DURATION = 400L;

   // ========== ЧАСТИЦЫ УРОНА ==========
   private static final float SHAKE_INTENSITY = 2.0F;
   private static final int PARTICLE_COUNT_PER_HURT = 4;
   private static final int PARTICLE_LIFETIME = 12;
   private static final float PARTICLE_SPEED = 1.8F;
   private static final Random RANDOM = new Random();

   // ========== АНИМАЦИИ ==========
   private final Animation fadeAnimation = new Animation(FADE_DURATION, Easing.SINE_OUT);
   private final Animation healthAnimation = new Animation(300L, Easing.CUBIC_OUT);
   private final Animation lagHealthAnimation = new Animation(HEALTH_LAG_DURATION, Easing.CUBIC_OUT);
   private final Animation absorptionAnimation = new Animation(250L, Easing.CUBIC_OUT);
   private final Animation itemSpinAnimation = new Animation(ITEM_SPIN_DURATION, Easing.BACK_OUT);
   private final Animation headPopAnimation = new Animation(200L, Easing.BACK_OUT);
   private final Animation hpPulseAnimation = new Animation(600L, Easing.SINE_IN_OUT);

   // ========== СОСТОЯНИЕ ==========
   private LivingEntity target;
   private final Map<UUID, Identifier> skinCache = new HashMap<>();
   private final List<Particle> particles = new ArrayList<>();

   // ========== КОНСТРУКТОР ==========
   public TargetHudComponent(String name, float initialX, float initialY, float windowWidth, float windowHeight,
                             float offsetX, float offsetY, DraggableHudElement.Align align) {
      super(name, initialX, initialY, windowWidth, windowHeight, offsetX, offsetY, align);
   }

   // ========== ОСНОВНОЙ РЕНДЕР ==========
   @Native
   public void render(CustomDrawContext ctx) {
      Aura aura = Aura.INSTANCE;
      LivingEntity newTarget = (mc.currentScreen instanceof ChatScreen) ? mc.player : aura.getTarget();

      updateTargetState(newTarget);
      fadeAnimation.update(target != null);
      headPopAnimation.update(target != null);

      float fade = fadeAnimation.getValue();
      if (fade < 0.01F) return;

      if (target != null) {
         renderTargetHud(ctx, target, fade);
      }
   }

   private void updateTargetState(LivingEntity newTarget) {
      if (newTarget == null) {
         target = null;
         particles.clear();
      } else {
         if (target != newTarget) {
            target = newTarget;
            particles.clear();
            healthAnimation.reset();
            lagHealthAnimation.reset();
            absorptionAnimation.reset();
            itemSpinAnimation.reset();
            itemSpinAnimation.setValue(1.0F);
            headPopAnimation.reset();
            headPopAnimation.setValue(1.0F);

            float maxHealth = target.getMaxHealth();
            float health = ScoreboardHealth.INSTANCE.isEnabled()
                    ? PlayerIntersectionUtil.getHealth(target)
                    : target.getHealth();
            healthAnimation.setValue(health / maxHealth);
            lagHealthAnimation.setValue(health / maxHealth);
            absorptionAnimation.setValue(target.getAbsorptionAmount() / maxHealth);
         }
      }
   }

   // ========== РЕНДЕР ХУДА ==========
   @Native
   private void renderTargetHud(CustomDrawContext ctx, LivingEntity target, float fade) {
      Theme theme = Mendix.getInstance().getThemeManager().getCurrentTheme();
      ColorRGBA themeColor = theme.getColor();
      ColorRGBA themeSecond = theme.getSecondColor();

      float x = this.x;
      float y = this.y;
      float contentX = x + PADDING + HEAD_SIZE + 6F;
      float contentWidth = WIDTH - (PADDING + HEAD_SIZE + 6F) - PADDING;
      float contentY = y + PADDING;

      // --- ТЕНЬ ПОД ХУДОМ ---
      DrawUtil.drawRoundedRect(ctx.getMatrices(), x + 2, y + 2, WIDTH, HEIGHT,
              BorderRadius.all(8F), new ColorRGBA(0, 0, 0, 60 * fade));

      // --- ФОН (СТЕКЛО) ---
      DrawUtil.drawBlur(ctx.getMatrices(), x, y, WIDTH, HEIGHT, 12F,
              BorderRadius.all(8F), new ColorRGBA(80, 80, 80, 160 * fade));
      DrawUtil.drawRoundedRect(ctx.getMatrices(), x, y, WIDTH, HEIGHT,
              BorderRadius.all(8F), new ColorRGBA(10, 10, 10, 220 * fade));

      // --- ОБВОДКА — ЦВЕТ ТЕМЫ (ХАРАКТЕРНЫЙ ТЕМЕ) ---
      ColorRGBA borderColor = themeColor.mix(themeSecond, 0.5F).withAlpha(255 * fade);
      DrawUtil.drawRoundedBorder(ctx.getMatrices(), x, y, WIDTH, HEIGHT, OUTLINE_WIDTH,
              BorderRadius.all(8F), borderColor);

      // --- АВАТАРКА ---
      Identifier skin = getSkinTexture(target);
      float headSize = HEAD_SIZE * (0.9F + 0.1F * headPopAnimation.getValue());
      float headX = x + PADDING + (HEAD_SIZE - headSize) / 2;
      float headY = y + PADDING + (HEAD_SIZE - headSize) / 2;

      DrawUtil.drawRoundedRect(ctx.getMatrices(), headX - 2, headY - 2, headSize + 4, headSize + 4,
              BorderRadius.all(8F), themeColor.withAlpha(80 * fade));

      boolean isHurt = target.hurtTime > 0;
      if (isHurt) {
         ctx.getMatrices().push();
         float shakeX = (RANDOM.nextFloat() - 0.5F) * SHAKE_INTENSITY;
         float shakeY = (RANDOM.nextFloat() - 0.5F) * SHAKE_INTENSITY;
         ctx.getMatrices().translate(shakeX, shakeY, 0);
         spawnDamageParticles(headX + headSize / 2, headY + headSize / 2, themeColor);
      }

      DrawUtil.drawPlayerHeadWithRoundedShader(ctx.getMatrices(), skin,
              headX, headY, headSize,
              BorderRadius.all(6F), ColorRGBA.WHITE.withAlpha(255 * fade));

      if (isHurt) {
         ctx.getMatrices().pop();
      }

      updateParticles();
      renderParticles(ctx, ctx.getMatrices(), fade);

      // --- ИМЯ ЦЕЛИ ---
      String name = (target == mc.player && NameProtect.INSTANCE.isEnabled())
              ? NameProtect.getCustomName()
              : target.getNameForScoreboard();

      MsdfRenderer.renderText(Fonts.BOLD, name, 9F,
              new ColorRGBA(0, 0, 0, 100 * fade).getRGB(),
              ctx.getMatrices().peek().getPositionMatrix(),
              contentX + 1, contentY + 1F, 0F, true, 0.7F, 1F, contentWidth);
      MsdfRenderer.renderText(Fonts.BOLD, name, 9F,
              ColorRGBA.WHITE.withAlpha(255 * fade).getRGB(),
              ctx.getMatrices().peek().getPositionMatrix(),
              contentX, contentY, 0F, true, 0.7F, 1F, contentWidth);

      // --- РАССТОЯНИЕ ---
      if (mc.player != null) {
         float dist = mc.player.distanceTo(target);
         String distText = String.format(Locale.US, "%.1f м", dist);
         MsdfRenderer.renderText(Fonts.REGULAR, distText, 7F,
                 new ColorRGBA(180, 180, 180, 200 * fade).getRGB(),
                 ctx.getMatrices().peek().getPositionMatrix(),
                 contentX, contentY + 10F, 0F, true, 0.7F, 1F, contentWidth);
      }

      // --- ПОЛОСКА ЗДОРОВЬЯ ---
      float maxHealth = target.getMaxHealth();
      float health = ScoreboardHealth.INSTANCE.isEnabled()
              ? PlayerIntersectionUtil.getHealth(target)
              : target.getHealth();
      float healthPercentCurrent = health / maxHealth;
      float absorptionPercent = target.getAbsorptionAmount() / maxHealth;

      healthAnimation.update(healthPercentCurrent);
      absorptionAnimation.update(absorptionPercent);

      if (lagHealthAnimation.getValue() > healthPercentCurrent) {
         lagHealthAnimation.update(healthPercentCurrent);
      } else {
         lagHealthAnimation.setValue(healthPercentCurrent);
      }

      float barY = y + HEIGHT - PADDING - BAR_HEIGHT;

      DrawUtil.drawRoundedRect(ctx.getMatrices(), contentX, barY, contentWidth, BAR_HEIGHT,
              BorderRadius.all(BAR_RADIUS), new ColorRGBA(20, 20, 20, 255 * fade));

      float lagWidth = contentWidth * lagHealthAnimation.getValue();
      if (lagWidth > 0) {
         DrawUtil.drawRoundedRect(ctx.getMatrices(), contentX, barY, lagWidth, BAR_HEIGHT,
                 BorderRadius.all(BAR_RADIUS), new ColorRGBA(150, 50, 50, 150 * fade));
      }

      float healthWidth = contentWidth * healthAnimation.getValue();
      if (healthWidth > 0) {
         ColorRGBA healthColor1 = interpolateColorGradient(healthPercentCurrent);
         ColorRGBA healthColor2 = healthColor1.darker(0.8F);
         DrawUtil.drawRoundedRect(ctx.getMatrices(), contentX, barY, healthWidth, BAR_HEIGHT,
                 BorderRadius.all(BAR_RADIUS),
                 healthColor1.withAlpha(255 * fade), healthColor1.withAlpha(255 * fade),
                 healthColor2.withAlpha(255 * fade), healthColor2.withAlpha(255 * fade));
      }

      hpPulseAnimation.update(healthPercentCurrent < 0.2F);
      float pulseGlow = hpPulseAnimation.getValue() * 0.3F;
      if (healthPercentCurrent < 0.2F) {
         DrawUtil.drawRoundedRect(ctx.getMatrices(),
                 contentX - 1, barY - 1, healthWidth + 2, BAR_HEIGHT + 2,
                 BorderRadius.all(BAR_RADIUS + 1),
                 new ColorRGBA(255, 50, 50, (int)(80 * fade * pulseGlow)));
      }

      float absorptionWidth = contentWidth * absorptionAnimation.getValue();
      if (absorptionWidth > 0) {
         float sparkle = (MathHelper.sin(mc.player.age * 0.3F) * 0.5F + 0.5F) * 0.5F + 0.5F;
         DrawUtil.drawRoundedRect(ctx.getMatrices(),
                 contentX, barY - 1.5F, absorptionWidth, 2.5F,
                 BorderRadius.all(1.5F),
                 new ColorRGBA(255, 215, 0, (int)(200 * fade * sparkle)));
      }

      // --- ТЕКСТ HP — СПРАВА НАД ПОЛОСКОЙ ---
      String hpText = String.format(Locale.US, "%.0f", health);
      float hpFontSize = 6F;
      float hpWidth = Fonts.REGULAR.getFont(hpFontSize).width(hpText);
      float hpX = contentX + contentWidth - hpWidth - 2F;
      float hpY = barY - 8F;

      ctx.drawText(Fonts.REGULAR.getFont(hpFontSize), hpText,
              hpX + 1, hpY + 1,
              new ColorRGBA(0, 0, 0, 100 * fade));
      ctx.drawText(Fonts.REGULAR.getFont(hpFontSize), hpText,
              hpX, hpY,
              ColorRGBA.WHITE.withAlpha(230 * fade));

      // --- БРОНЯ ---
      if (target instanceof PlayerEntity) {
         renderArmorAndItems(ctx, (PlayerEntity) target, x, y + HEIGHT + 4F, WIDTH, fade);
      }

      this.width = WIDTH;
      this.height = HEIGHT;
   }

   // ========== ЦВЕТ ЗДОРОВЬЯ ==========
   private ColorRGBA interpolateColorGradient(float percent) {
      if (percent > 0.8F) return new ColorRGBA(50, 255, 50);
      if (percent > 0.5F) return new ColorRGBA(255, 255, 50);
      if (percent > 0.2F) return new ColorRGBA(255, 150, 50);
      return new ColorRGBA(255, 50, 50);
   }

   // ========== ЧАСТИЦЫ УРОНА ==========
   private void spawnDamageParticles(float centerX, float centerY, ColorRGBA themeColor) {
      ColorRGBA baseColor = themeColor.mix(ColorRGBA.RED, 0.5F);

      for (int i = 0; i < PARTICLE_COUNT_PER_HURT; i++) {
         float angle = RANDOM.nextFloat() * (float) Math.PI * 2;
         float speed = PARTICLE_SPEED * (0.7F + RANDOM.nextFloat() * 0.6F);
         float vx = (float) Math.cos(angle) * speed;
         float vy = (float) Math.sin(angle) * speed - 0.5F;

         int lifetime = PARTICLE_LIFETIME + RANDOM.nextInt(6) - 3;
         float variation = 0.8F + RANDOM.nextFloat() * 0.4F;

         int r = (int) MathHelper.clamp(baseColor.getRed() * variation, 0, 255);
         int g = (int) MathHelper.clamp(baseColor.getGreen() * variation, 0, 255);
         int b = (int) MathHelper.clamp(baseColor.getBlue() * variation, 0, 255);
         int a = baseColor.getAlpha();

         ColorRGBA particleColor = new ColorRGBA(r, g, b, a);
         particles.add(new Particle(centerX, centerY, vx, vy, lifetime, particleColor));
      }
   }

   private void updateParticles() {
      particles.removeIf(p -> {
         p.update();
         return !p.isAlive();
      });
   }

   private void renderParticles(CustomDrawContext ctx, MatrixStack matrices, float fade) {
      if (particles.isEmpty()) return;

      RenderSystem.enableBlend();
      RenderSystem.defaultBlendFunc();
      RenderSystem.disableDepthTest();
      RenderSystem.depthMask(false);
      RenderSystem.setShader(ShaderProgramKeys.POSITION_COLOR);

      Matrix4f matrix = matrices.peek().getPositionMatrix();
      BufferBuilder buffer = Tessellator.getInstance().begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR);

      for (Particle p : particles) {
         float alpha = (float) p.life / p.maxLife * fade;
         int a = (int) (alpha * 255);
         int color = p.color.withAlpha(a).getRGB();

         float size = 1.5F + (1.0F - (float) p.life / p.maxLife) * 1.0F;
         float x1 = p.x - size;
         float y1 = p.y - size;
         float x2 = p.x + size;
         float y2 = p.y + size;

         int r = (color >> 16) & 0xFF;
         int g = (color >> 8) & 0xFF;
         int b = color & 0xFF;
         int a2 = (color >> 24) & 0xFF;

         buffer.vertex(matrix, x1, y2, 0).color(r, g, b, a2);
         buffer.vertex(matrix, x2, y2, 0).color(r, g, b, a2);
         buffer.vertex(matrix, x2, y1, 0).color(r, g, b, a2);
         buffer.vertex(matrix, x1, y1, 0).color(r, g, b, a2);
      }

      BufferRenderer.drawWithGlobalProgram(buffer.end());

      RenderSystem.enableDepthTest();
      RenderSystem.depthMask(true);
      RenderSystem.disableBlend();
   }

   // ========== БРОНЯ И ПРЕДМЕТЫ ==========
   private void renderArmorAndItems(CustomDrawContext ctx, PlayerEntity player, float baseX, float baseY, float hudWidth, float fade) {
      List<ItemStack> armor = player.getInventory().armor;
      ItemStack[] items = {
              player.getMainHandStack(),
              player.getOffHandStack(),
              armor.get(3),
              armor.get(2),
              armor.get(1),
              armor.get(0)
      };

      int count = 0;
      for (ItemStack stack : items) if (!stack.isEmpty()) count++;
      if (count == 0) return;

      float totalWidth = count * ARMOR_ICON_SIZE;
      float startX = baseX + (hudWidth - totalWidth) / 2F;
      float currentX = startX;

      DrawUtil.drawRoundedRect(ctx.getMatrices(),
              startX - 3, baseY - 2,
              totalWidth + 6, ARMOR_ICON_SIZE + 4,
              BorderRadius.all(4F),
              new ColorRGBA(20, 20, 20, 150 * fade));

      itemSpinAnimation.update(true);
      float spin = itemSpinAnimation.getValue();

      for (ItemStack stack : items) {
         if (!stack.isEmpty()) {
            ctx.getMatrices().push();
            ctx.getMatrices().translate(
                    currentX + ARMOR_ICON_SIZE / 2F,
                    baseY + ARMOR_ICON_SIZE / 2F,
                    0);
            ctx.getMatrices().multiply(RotationAxis.POSITIVE_Z.rotationDegrees(360 * (1 - spin)));
            ctx.getMatrices().scale(ARMOR_SCALE * (0.9F + 0.1F * spin),
                    ARMOR_SCALE * (0.9F + 0.1F * spin),
                    1);
            ctx.getMatrices().translate(-8, -8, 0);
            ctx.drawItem(stack, 0, 0);
            ((DrawContextAccessor) ctx).callDrawItemBar(stack, 0, 0);
            ctx.getMatrices().pop();
            currentX += ARMOR_ICON_SIZE;
         }
      }
   }

   // ========== ЭФФЕКТЫ ==========

   private String formatEffectTime(int ticks) {
      int seconds = ticks / 20;
      int minutes = seconds / 60;
      seconds %= 60;
      return String.format(Locale.US, "%d:%02d", minutes, seconds);
   }

   // ========== КЕШИРОВАНИЕ СКИНОВ ==========
   private Identifier getSkinTexture(LivingEntity entity) {
      if (!(entity instanceof PlayerEntity)) {
         return DefaultSkinHelper.getSteve().texture();
      }
      UUID uuid = entity.getUuid();
      if (skinCache.containsKey(uuid)) {
         return skinCache.get(uuid);
      }

      Identifier skin = DefaultSkinHelper.getSteve().texture();
      if (mc.getNetworkHandler() != null) {
         for (PlayerListEntry entry : mc.getNetworkHandler().getPlayerList()) {
            if (entry.getProfile().getId().equals(uuid)) {
               skin = entry.getSkinTextures().texture();
               break;
            }
         }
      }
      skinCache.put(uuid, skin);
      return skin;
   }

   public void setTarget(LivingEntity target) {
      this.target = target;
   }

   // ========== КЛАСС ЧАСТИЦЫ ==========
   private static class Particle {
      float x, y;
      float vx, vy;
      int life;
      int maxLife;
      ColorRGBA color;

      Particle(float x, float y, float vx, float vy, int maxLife, ColorRGBA color) {
         this.x = x;
         this.y = y;
         this.vx = vx;
         this.vy = vy;
         this.maxLife = maxLife;
         this.life = maxLife;
         this.color = color;
      }

      boolean isAlive() {
         return life > 0;
      }

      void update() {
         x += vx;
         y += vy;
         vy += 0.05F;
         life--;
      }
   }
}
А в чем прикол добавлять метры? Это же бесполезно
 
SS Снизу
Короче вроде норм, но через нейронку

Посмотреть вложение 327492



TargetHudComponent:
Expand Collapse Copy
package fun.mendix.client.hud.elements.component;

import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gl.ShaderProgramKeys;
import net.minecraft.client.gui.screen.ChatScreen;
import net.minecraft.client.network.PlayerListEntry;
import net.minecraft.client.render.*;
import net.minecraft.client.texture.Sprite;
import net.minecraft.client.util.DefaultSkinHelper;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.effect.StatusEffectInstance;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.RotationAxis;
import org.joml.Matrix4f;
import ru.nexusguard.protection.annotations.Native;
import fun.mendix.Mendix;
import fun.mendix.base.animations.base.Animation;
import fun.mendix.base.animations.base.Easing;
import fun.mendix.base.font.Fonts;
import fun.mendix.base.font.MsdfRenderer;
import fun.mendix.base.theme.Theme;
import fun.mendix.client.hud.elements.draggable.DraggableHudElement;
import fun.mendix.client.modules.impl.combat.Aura;
import fun.mendix.client.modules.impl.misc.NameProtect;
import fun.mendix.client.modules.impl.misc.ScoreboardHealth;
import fun.mendix.utility.game.player.PlayerIntersectionUtil;
import fun.mendix.utility.mixin.accessors.DrawContextAccessor;
import fun.mendix.utility.render.display.base.BorderRadius;
import fun.mendix.utility.render.display.base.CustomDrawContext;
import fun.mendix.utility.render.display.base.color.ColorRGBA;
import fun.mendix.utility.render.display.shader.DrawUtil;

import java.util.*;

public class TargetHudComponent extends DraggableHudElement {

   // ========== КОНСТАНТЫ ==========
   private static final float WIDTH = 130F;
   private static final float HEIGHT = 46F;
   private static final float PADDING = 6F;
   private static final float HEAD_SIZE = 28F;
   private static final float BAR_HEIGHT = 4F;
   private static final float BAR_RADIUS = 2F;
   private static final float OUTLINE_WIDTH = 1.8F;
   private static final float ARMOR_ICON_SIZE = 10F;
   private static final float ARMOR_SCALE = 0.65F;
   private static final float EFFECT_ICON_SIZE = 14F;
   private static final long FADE_DURATION = 250L;
   private static final long HEALTH_LAG_DURATION = 700L;
   private static final long ITEM_SPIN_DURATION = 400L;

   // ========== ЧАСТИЦЫ УРОНА ==========
   private static final float SHAKE_INTENSITY = 2.0F;
   private static final int PARTICLE_COUNT_PER_HURT = 4;
   private static final int PARTICLE_LIFETIME = 12;
   private static final float PARTICLE_SPEED = 1.8F;
   private static final Random RANDOM = new Random();

   // ========== АНИМАЦИИ ==========
   private final Animation fadeAnimation = new Animation(FADE_DURATION, Easing.SINE_OUT);
   private final Animation healthAnimation = new Animation(300L, Easing.CUBIC_OUT);
   private final Animation lagHealthAnimation = new Animation(HEALTH_LAG_DURATION, Easing.CUBIC_OUT);
   private final Animation absorptionAnimation = new Animation(250L, Easing.CUBIC_OUT);
   private final Animation itemSpinAnimation = new Animation(ITEM_SPIN_DURATION, Easing.BACK_OUT);
   private final Animation headPopAnimation = new Animation(200L, Easing.BACK_OUT);
   private final Animation hpPulseAnimation = new Animation(600L, Easing.SINE_IN_OUT);

   // ========== СОСТОЯНИЕ ==========
   private LivingEntity target;
   private final Map<UUID, Identifier> skinCache = new HashMap<>();
   private final List<Particle> particles = new ArrayList<>();

   // ========== КОНСТРУКТОР ==========
   public TargetHudComponent(String name, float initialX, float initialY, float windowWidth, float windowHeight,
                             float offsetX, float offsetY, DraggableHudElement.Align align) {
      super(name, initialX, initialY, windowWidth, windowHeight, offsetX, offsetY, align);
   }

   // ========== ОСНОВНОЙ РЕНДЕР ==========
   @Native
   public void render(CustomDrawContext ctx) {
      Aura aura = Aura.INSTANCE;
      LivingEntity newTarget = (mc.currentScreen instanceof ChatScreen) ? mc.player : aura.getTarget();

      updateTargetState(newTarget);
      fadeAnimation.update(target != null);
      headPopAnimation.update(target != null);

      float fade = fadeAnimation.getValue();
      if (fade < 0.01F) return;

      if (target != null) {
         renderTargetHud(ctx, target, fade);
      }
   }

   private void updateTargetState(LivingEntity newTarget) {
      if (newTarget == null) {
         target = null;
         particles.clear();
      } else {
         if (target != newTarget) {
            target = newTarget;
            particles.clear();
            healthAnimation.reset();
            lagHealthAnimation.reset();
            absorptionAnimation.reset();
            itemSpinAnimation.reset();
            itemSpinAnimation.setValue(1.0F);
            headPopAnimation.reset();
            headPopAnimation.setValue(1.0F);

            float maxHealth = target.getMaxHealth();
            float health = ScoreboardHealth.INSTANCE.isEnabled()
                    ? PlayerIntersectionUtil.getHealth(target)
                    : target.getHealth();
            healthAnimation.setValue(health / maxHealth);
            lagHealthAnimation.setValue(health / maxHealth);
            absorptionAnimation.setValue(target.getAbsorptionAmount() / maxHealth);
         }
      }
   }

   // ========== РЕНДЕР ХУДА ==========
   @Native
   private void renderTargetHud(CustomDrawContext ctx, LivingEntity target, float fade) {
      Theme theme = Mendix.getInstance().getThemeManager().getCurrentTheme();
      ColorRGBA themeColor = theme.getColor();
      ColorRGBA themeSecond = theme.getSecondColor();

      float x = this.x;
      float y = this.y;
      float contentX = x + PADDING + HEAD_SIZE + 6F;
      float contentWidth = WIDTH - (PADDING + HEAD_SIZE + 6F) - PADDING;
      float contentY = y + PADDING;

      // --- ТЕНЬ ПОД ХУДОМ ---
      DrawUtil.drawRoundedRect(ctx.getMatrices(), x + 2, y + 2, WIDTH, HEIGHT,
              BorderRadius.all(8F), new ColorRGBA(0, 0, 0, 60 * fade));

      // --- ФОН (СТЕКЛО) ---
      DrawUtil.drawBlur(ctx.getMatrices(), x, y, WIDTH, HEIGHT, 12F,
              BorderRadius.all(8F), new ColorRGBA(80, 80, 80, 160 * fade));
      DrawUtil.drawRoundedRect(ctx.getMatrices(), x, y, WIDTH, HEIGHT,
              BorderRadius.all(8F), new ColorRGBA(10, 10, 10, 220 * fade));

      // --- ОБВОДКА — ЦВЕТ ТЕМЫ (ХАРАКТЕРНЫЙ ТЕМЕ) ---
      ColorRGBA borderColor = themeColor.mix(themeSecond, 0.5F).withAlpha(255 * fade);
      DrawUtil.drawRoundedBorder(ctx.getMatrices(), x, y, WIDTH, HEIGHT, OUTLINE_WIDTH,
              BorderRadius.all(8F), borderColor);

      // --- АВАТАРКА ---
      Identifier skin = getSkinTexture(target);
      float headSize = HEAD_SIZE * (0.9F + 0.1F * headPopAnimation.getValue());
      float headX = x + PADDING + (HEAD_SIZE - headSize) / 2;
      float headY = y + PADDING + (HEAD_SIZE - headSize) / 2;

      DrawUtil.drawRoundedRect(ctx.getMatrices(), headX - 2, headY - 2, headSize + 4, headSize + 4,
              BorderRadius.all(8F), themeColor.withAlpha(80 * fade));

      boolean isHurt = target.hurtTime > 0;
      if (isHurt) {
         ctx.getMatrices().push();
         float shakeX = (RANDOM.nextFloat() - 0.5F) * SHAKE_INTENSITY;
         float shakeY = (RANDOM.nextFloat() - 0.5F) * SHAKE_INTENSITY;
         ctx.getMatrices().translate(shakeX, shakeY, 0);
         spawnDamageParticles(headX + headSize / 2, headY + headSize / 2, themeColor);
      }

      DrawUtil.drawPlayerHeadWithRoundedShader(ctx.getMatrices(), skin,
              headX, headY, headSize,
              BorderRadius.all(6F), ColorRGBA.WHITE.withAlpha(255 * fade));

      if (isHurt) {
         ctx.getMatrices().pop();
      }

      updateParticles();
      renderParticles(ctx, ctx.getMatrices(), fade);

      // --- ИМЯ ЦЕЛИ ---
      String name = (target == mc.player && NameProtect.INSTANCE.isEnabled())
              ? NameProtect.getCustomName()
              : target.getNameForScoreboard();

      MsdfRenderer.renderText(Fonts.BOLD, name, 9F,
              new ColorRGBA(0, 0, 0, 100 * fade).getRGB(),
              ctx.getMatrices().peek().getPositionMatrix(),
              contentX + 1, contentY + 1F, 0F, true, 0.7F, 1F, contentWidth);
      MsdfRenderer.renderText(Fonts.BOLD, name, 9F,
              ColorRGBA.WHITE.withAlpha(255 * fade).getRGB(),
              ctx.getMatrices().peek().getPositionMatrix(),
              contentX, contentY, 0F, true, 0.7F, 1F, contentWidth);

      // --- РАССТОЯНИЕ ---
      if (mc.player != null) {
         float dist = mc.player.distanceTo(target);
         String distText = String.format(Locale.US, "%.1f м", dist);
         MsdfRenderer.renderText(Fonts.REGULAR, distText, 7F,
                 new ColorRGBA(180, 180, 180, 200 * fade).getRGB(),
                 ctx.getMatrices().peek().getPositionMatrix(),
                 contentX, contentY + 10F, 0F, true, 0.7F, 1F, contentWidth);
      }

      // --- ПОЛОСКА ЗДОРОВЬЯ ---
      float maxHealth = target.getMaxHealth();
      float health = ScoreboardHealth.INSTANCE.isEnabled()
              ? PlayerIntersectionUtil.getHealth(target)
              : target.getHealth();
      float healthPercentCurrent = health / maxHealth;
      float absorptionPercent = target.getAbsorptionAmount() / maxHealth;

      healthAnimation.update(healthPercentCurrent);
      absorptionAnimation.update(absorptionPercent);

      if (lagHealthAnimation.getValue() > healthPercentCurrent) {
         lagHealthAnimation.update(healthPercentCurrent);
      } else {
         lagHealthAnimation.setValue(healthPercentCurrent);
      }

      float barY = y + HEIGHT - PADDING - BAR_HEIGHT;

      DrawUtil.drawRoundedRect(ctx.getMatrices(), contentX, barY, contentWidth, BAR_HEIGHT,
              BorderRadius.all(BAR_RADIUS), new ColorRGBA(20, 20, 20, 255 * fade));

      float lagWidth = contentWidth * lagHealthAnimation.getValue();
      if (lagWidth > 0) {
         DrawUtil.drawRoundedRect(ctx.getMatrices(), contentX, barY, lagWidth, BAR_HEIGHT,
                 BorderRadius.all(BAR_RADIUS), new ColorRGBA(150, 50, 50, 150 * fade));
      }

      float healthWidth = contentWidth * healthAnimation.getValue();
      if (healthWidth > 0) {
         ColorRGBA healthColor1 = interpolateColorGradient(healthPercentCurrent);
         ColorRGBA healthColor2 = healthColor1.darker(0.8F);
         DrawUtil.drawRoundedRect(ctx.getMatrices(), contentX, barY, healthWidth, BAR_HEIGHT,
                 BorderRadius.all(BAR_RADIUS),
                 healthColor1.withAlpha(255 * fade), healthColor1.withAlpha(255 * fade),
                 healthColor2.withAlpha(255 * fade), healthColor2.withAlpha(255 * fade));
      }

      hpPulseAnimation.update(healthPercentCurrent < 0.2F);
      float pulseGlow = hpPulseAnimation.getValue() * 0.3F;
      if (healthPercentCurrent < 0.2F) {
         DrawUtil.drawRoundedRect(ctx.getMatrices(),
                 contentX - 1, barY - 1, healthWidth + 2, BAR_HEIGHT + 2,
                 BorderRadius.all(BAR_RADIUS + 1),
                 new ColorRGBA(255, 50, 50, (int)(80 * fade * pulseGlow)));
      }

      float absorptionWidth = contentWidth * absorptionAnimation.getValue();
      if (absorptionWidth > 0) {
         float sparkle = (MathHelper.sin(mc.player.age * 0.3F) * 0.5F + 0.5F) * 0.5F + 0.5F;
         DrawUtil.drawRoundedRect(ctx.getMatrices(),
                 contentX, barY - 1.5F, absorptionWidth, 2.5F,
                 BorderRadius.all(1.5F),
                 new ColorRGBA(255, 215, 0, (int)(200 * fade * sparkle)));
      }

      // --- ТЕКСТ HP — СПРАВА НАД ПОЛОСКОЙ ---
      String hpText = String.format(Locale.US, "%.0f", health);
      float hpFontSize = 6F;
      float hpWidth = Fonts.REGULAR.getFont(hpFontSize).width(hpText);
      float hpX = contentX + contentWidth - hpWidth - 2F;
      float hpY = barY - 8F;

      ctx.drawText(Fonts.REGULAR.getFont(hpFontSize), hpText,
              hpX + 1, hpY + 1,
              new ColorRGBA(0, 0, 0, 100 * fade));
      ctx.drawText(Fonts.REGULAR.getFont(hpFontSize), hpText,
              hpX, hpY,
              ColorRGBA.WHITE.withAlpha(230 * fade));

      // --- БРОНЯ ---
      if (target instanceof PlayerEntity) {
         renderArmorAndItems(ctx, (PlayerEntity) target, x, y + HEIGHT + 4F, WIDTH, fade);
      }

      this.width = WIDTH;
      this.height = HEIGHT;
   }

   // ========== ЦВЕТ ЗДОРОВЬЯ ==========
   private ColorRGBA interpolateColorGradient(float percent) {
      if (percent > 0.8F) return new ColorRGBA(50, 255, 50);
      if (percent > 0.5F) return new ColorRGBA(255, 255, 50);
      if (percent > 0.2F) return new ColorRGBA(255, 150, 50);
      return new ColorRGBA(255, 50, 50);
   }

   // ========== ЧАСТИЦЫ УРОНА ==========
   private void spawnDamageParticles(float centerX, float centerY, ColorRGBA themeColor) {
      ColorRGBA baseColor = themeColor.mix(ColorRGBA.RED, 0.5F);

      for (int i = 0; i < PARTICLE_COUNT_PER_HURT; i++) {
         float angle = RANDOM.nextFloat() * (float) Math.PI * 2;
         float speed = PARTICLE_SPEED * (0.7F + RANDOM.nextFloat() * 0.6F);
         float vx = (float) Math.cos(angle) * speed;
         float vy = (float) Math.sin(angle) * speed - 0.5F;

         int lifetime = PARTICLE_LIFETIME + RANDOM.nextInt(6) - 3;
         float variation = 0.8F + RANDOM.nextFloat() * 0.4F;

         int r = (int) MathHelper.clamp(baseColor.getRed() * variation, 0, 255);
         int g = (int) MathHelper.clamp(baseColor.getGreen() * variation, 0, 255);
         int b = (int) MathHelper.clamp(baseColor.getBlue() * variation, 0, 255);
         int a = baseColor.getAlpha();

         ColorRGBA particleColor = new ColorRGBA(r, g, b, a);
         particles.add(new Particle(centerX, centerY, vx, vy, lifetime, particleColor));
      }
   }

   private void updateParticles() {
      particles.removeIf(p -> {
         p.update();
         return !p.isAlive();
      });
   }

   private void renderParticles(CustomDrawContext ctx, MatrixStack matrices, float fade) {
      if (particles.isEmpty()) return;

      RenderSystem.enableBlend();
      RenderSystem.defaultBlendFunc();
      RenderSystem.disableDepthTest();
      RenderSystem.depthMask(false);
      RenderSystem.setShader(ShaderProgramKeys.POSITION_COLOR);

      Matrix4f matrix = matrices.peek().getPositionMatrix();
      BufferBuilder buffer = Tessellator.getInstance().begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR);

      for (Particle p : particles) {
         float alpha = (float) p.life / p.maxLife * fade;
         int a = (int) (alpha * 255);
         int color = p.color.withAlpha(a).getRGB();

         float size = 1.5F + (1.0F - (float) p.life / p.maxLife) * 1.0F;
         float x1 = p.x - size;
         float y1 = p.y - size;
         float x2 = p.x + size;
         float y2 = p.y + size;

         int r = (color >> 16) & 0xFF;
         int g = (color >> 8) & 0xFF;
         int b = color & 0xFF;
         int a2 = (color >> 24) & 0xFF;

         buffer.vertex(matrix, x1, y2, 0).color(r, g, b, a2);
         buffer.vertex(matrix, x2, y2, 0).color(r, g, b, a2);
         buffer.vertex(matrix, x2, y1, 0).color(r, g, b, a2);
         buffer.vertex(matrix, x1, y1, 0).color(r, g, b, a2);
      }

      BufferRenderer.drawWithGlobalProgram(buffer.end());

      RenderSystem.enableDepthTest();
      RenderSystem.depthMask(true);
      RenderSystem.disableBlend();
   }

   // ========== БРОНЯ И ПРЕДМЕТЫ ==========
   private void renderArmorAndItems(CustomDrawContext ctx, PlayerEntity player, float baseX, float baseY, float hudWidth, float fade) {
      List<ItemStack> armor = player.getInventory().armor;
      ItemStack[] items = {
              player.getMainHandStack(),
              player.getOffHandStack(),
              armor.get(3),
              armor.get(2),
              armor.get(1),
              armor.get(0)
      };

      int count = 0;
      for (ItemStack stack : items) if (!stack.isEmpty()) count++;
      if (count == 0) return;

      float totalWidth = count * ARMOR_ICON_SIZE;
      float startX = baseX + (hudWidth - totalWidth) / 2F;
      float currentX = startX;

      DrawUtil.drawRoundedRect(ctx.getMatrices(),
              startX - 3, baseY - 2,
              totalWidth + 6, ARMOR_ICON_SIZE + 4,
              BorderRadius.all(4F),
              new ColorRGBA(20, 20, 20, 150 * fade));

      itemSpinAnimation.update(true);
      float spin = itemSpinAnimation.getValue();

      for (ItemStack stack : items) {
         if (!stack.isEmpty()) {
            ctx.getMatrices().push();
            ctx.getMatrices().translate(
                    currentX + ARMOR_ICON_SIZE / 2F,
                    baseY + ARMOR_ICON_SIZE / 2F,
                    0);
            ctx.getMatrices().multiply(RotationAxis.POSITIVE_Z.rotationDegrees(360 * (1 - spin)));
            ctx.getMatrices().scale(ARMOR_SCALE * (0.9F + 0.1F * spin),
                    ARMOR_SCALE * (0.9F + 0.1F * spin),
                    1);
            ctx.getMatrices().translate(-8, -8, 0);
            ctx.drawItem(stack, 0, 0);
            ((DrawContextAccessor) ctx).callDrawItemBar(stack, 0, 0);
            ctx.getMatrices().pop();
            currentX += ARMOR_ICON_SIZE;
         }
      }
   }

   // ========== ЭФФЕКТЫ ==========

   private String formatEffectTime(int ticks) {
      int seconds = ticks / 20;
      int minutes = seconds / 60;
      seconds %= 60;
      return String.format(Locale.US, "%d:%02d", minutes, seconds);
   }

   // ========== КЕШИРОВАНИЕ СКИНОВ ==========
   private Identifier getSkinTexture(LivingEntity entity) {
      if (!(entity instanceof PlayerEntity)) {
         return DefaultSkinHelper.getSteve().texture();
      }
      UUID uuid = entity.getUuid();
      if (skinCache.containsKey(uuid)) {
         return skinCache.get(uuid);
      }

      Identifier skin = DefaultSkinHelper.getSteve().texture();
      if (mc.getNetworkHandler() != null) {
         for (PlayerListEntry entry : mc.getNetworkHandler().getPlayerList()) {
            if (entry.getProfile().getId().equals(uuid)) {
               skin = entry.getSkinTextures().texture();
               break;
            }
         }
      }
      skinCache.put(uuid, skin);
      return skin;
   }

   public void setTarget(LivingEntity target) {
      this.target = target;
   }

   // ========== КЛАСС ЧАСТИЦЫ ==========
   private static class Particle {
      float x, y;
      float vx, vy;
      int life;
      int maxLife;
      ColorRGBA color;

      Particle(float x, float y, float vx, float vy, int maxLife, ColorRGBA color) {
         this.x = x;
         this.y = y;
         this.vx = vx;
         this.vy = vy;
         this.maxLife = maxLife;
         this.life = maxLife;
         this.color = color;
      }

      boolean isAlive() {
         return life > 0;
      }

      void update() {
         x += vx;
         y += vy;
         vy += 0.05F;
         life--;
      }
   }
}
БЛЯТЬ БРАТАН это пиздос куда уехала голова и ник?
 
SS Снизу
Короче вроде норм, но через нейронку

Посмотреть вложение 327492



TargetHudComponent:
Expand Collapse Copy
package fun.mendix.client.hud.elements.component;

import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gl.ShaderProgramKeys;
import net.minecraft.client.gui.screen.ChatScreen;
import net.minecraft.client.network.PlayerListEntry;
import net.minecraft.client.render.*;
import net.minecraft.client.texture.Sprite;
import net.minecraft.client.util.DefaultSkinHelper;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.effect.StatusEffectInstance;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.RotationAxis;
import org.joml.Matrix4f;
import ru.nexusguard.protection.annotations.Native;
import fun.mendix.Mendix;
import fun.mendix.base.animations.base.Animation;
import fun.mendix.base.animations.base.Easing;
import fun.mendix.base.font.Fonts;
import fun.mendix.base.font.MsdfRenderer;
import fun.mendix.base.theme.Theme;
import fun.mendix.client.hud.elements.draggable.DraggableHudElement;
import fun.mendix.client.modules.impl.combat.Aura;
import fun.mendix.client.modules.impl.misc.NameProtect;
import fun.mendix.client.modules.impl.misc.ScoreboardHealth;
import fun.mendix.utility.game.player.PlayerIntersectionUtil;
import fun.mendix.utility.mixin.accessors.DrawContextAccessor;
import fun.mendix.utility.render.display.base.BorderRadius;
import fun.mendix.utility.render.display.base.CustomDrawContext;
import fun.mendix.utility.render.display.base.color.ColorRGBA;
import fun.mendix.utility.render.display.shader.DrawUtil;

import java.util.*;

public class TargetHudComponent extends DraggableHudElement {

   // ========== КОНСТАНТЫ ==========
   private static final float WIDTH = 130F;
   private static final float HEIGHT = 46F;
   private static final float PADDING = 6F;
   private static final float HEAD_SIZE = 28F;
   private static final float BAR_HEIGHT = 4F;
   private static final float BAR_RADIUS = 2F;
   private static final float OUTLINE_WIDTH = 1.8F;
   private static final float ARMOR_ICON_SIZE = 10F;
   private static final float ARMOR_SCALE = 0.65F;
   private static final float EFFECT_ICON_SIZE = 14F;
   private static final long FADE_DURATION = 250L;
   private static final long HEALTH_LAG_DURATION = 700L;
   private static final long ITEM_SPIN_DURATION = 400L;

   // ========== ЧАСТИЦЫ УРОНА ==========
   private static final float SHAKE_INTENSITY = 2.0F;
   private static final int PARTICLE_COUNT_PER_HURT = 4;
   private static final int PARTICLE_LIFETIME = 12;
   private static final float PARTICLE_SPEED = 1.8F;
   private static final Random RANDOM = new Random();

   // ========== АНИМАЦИИ ==========
   private final Animation fadeAnimation = new Animation(FADE_DURATION, Easing.SINE_OUT);
   private final Animation healthAnimation = new Animation(300L, Easing.CUBIC_OUT);
   private final Animation lagHealthAnimation = new Animation(HEALTH_LAG_DURATION, Easing.CUBIC_OUT);
   private final Animation absorptionAnimation = new Animation(250L, Easing.CUBIC_OUT);
   private final Animation itemSpinAnimation = new Animation(ITEM_SPIN_DURATION, Easing.BACK_OUT);
   private final Animation headPopAnimation = new Animation(200L, Easing.BACK_OUT);
   private final Animation hpPulseAnimation = new Animation(600L, Easing.SINE_IN_OUT);

   // ========== СОСТОЯНИЕ ==========
   private LivingEntity target;
   private final Map<UUID, Identifier> skinCache = new HashMap<>();
   private final List<Particle> particles = new ArrayList<>();

   // ========== КОНСТРУКТОР ==========
   public TargetHudComponent(String name, float initialX, float initialY, float windowWidth, float windowHeight,
                             float offsetX, float offsetY, DraggableHudElement.Align align) {
      super(name, initialX, initialY, windowWidth, windowHeight, offsetX, offsetY, align);
   }

   // ========== ОСНОВНОЙ РЕНДЕР ==========
   @Native
   public void render(CustomDrawContext ctx) {
      Aura aura = Aura.INSTANCE;
      LivingEntity newTarget = (mc.currentScreen instanceof ChatScreen) ? mc.player : aura.getTarget();

      updateTargetState(newTarget);
      fadeAnimation.update(target != null);
      headPopAnimation.update(target != null);

      float fade = fadeAnimation.getValue();
      if (fade < 0.01F) return;

      if (target != null) {
         renderTargetHud(ctx, target, fade);
      }
   }

   private void updateTargetState(LivingEntity newTarget) {
      if (newTarget == null) {
         target = null;
         particles.clear();
      } else {
         if (target != newTarget) {
            target = newTarget;
            particles.clear();
            healthAnimation.reset();
            lagHealthAnimation.reset();
            absorptionAnimation.reset();
            itemSpinAnimation.reset();
            itemSpinAnimation.setValue(1.0F);
            headPopAnimation.reset();
            headPopAnimation.setValue(1.0F);

            float maxHealth = target.getMaxHealth();
            float health = ScoreboardHealth.INSTANCE.isEnabled()
                    ? PlayerIntersectionUtil.getHealth(target)
                    : target.getHealth();
            healthAnimation.setValue(health / maxHealth);
            lagHealthAnimation.setValue(health / maxHealth);
            absorptionAnimation.setValue(target.getAbsorptionAmount() / maxHealth);
         }
      }
   }

   // ========== РЕНДЕР ХУДА ==========
   @Native
   private void renderTargetHud(CustomDrawContext ctx, LivingEntity target, float fade) {
      Theme theme = Mendix.getInstance().getThemeManager().getCurrentTheme();
      ColorRGBA themeColor = theme.getColor();
      ColorRGBA themeSecond = theme.getSecondColor();

      float x = this.x;
      float y = this.y;
      float contentX = x + PADDING + HEAD_SIZE + 6F;
      float contentWidth = WIDTH - (PADDING + HEAD_SIZE + 6F) - PADDING;
      float contentY = y + PADDING;

      // --- ТЕНЬ ПОД ХУДОМ ---
      DrawUtil.drawRoundedRect(ctx.getMatrices(), x + 2, y + 2, WIDTH, HEIGHT,
              BorderRadius.all(8F), new ColorRGBA(0, 0, 0, 60 * fade));

      // --- ФОН (СТЕКЛО) ---
      DrawUtil.drawBlur(ctx.getMatrices(), x, y, WIDTH, HEIGHT, 12F,
              BorderRadius.all(8F), new ColorRGBA(80, 80, 80, 160 * fade));
      DrawUtil.drawRoundedRect(ctx.getMatrices(), x, y, WIDTH, HEIGHT,
              BorderRadius.all(8F), new ColorRGBA(10, 10, 10, 220 * fade));

      // --- ОБВОДКА — ЦВЕТ ТЕМЫ (ХАРАКТЕРНЫЙ ТЕМЕ) ---
      ColorRGBA borderColor = themeColor.mix(themeSecond, 0.5F).withAlpha(255 * fade);
      DrawUtil.drawRoundedBorder(ctx.getMatrices(), x, y, WIDTH, HEIGHT, OUTLINE_WIDTH,
              BorderRadius.all(8F), borderColor);

      // --- АВАТАРКА ---
      Identifier skin = getSkinTexture(target);
      float headSize = HEAD_SIZE * (0.9F + 0.1F * headPopAnimation.getValue());
      float headX = x + PADDING + (HEAD_SIZE - headSize) / 2;
      float headY = y + PADDING + (HEAD_SIZE - headSize) / 2;

      DrawUtil.drawRoundedRect(ctx.getMatrices(), headX - 2, headY - 2, headSize + 4, headSize + 4,
              BorderRadius.all(8F), themeColor.withAlpha(80 * fade));

      boolean isHurt = target.hurtTime > 0;
      if (isHurt) {
         ctx.getMatrices().push();
         float shakeX = (RANDOM.nextFloat() - 0.5F) * SHAKE_INTENSITY;
         float shakeY = (RANDOM.nextFloat() - 0.5F) * SHAKE_INTENSITY;
         ctx.getMatrices().translate(shakeX, shakeY, 0);
         spawnDamageParticles(headX + headSize / 2, headY + headSize / 2, themeColor);
      }

      DrawUtil.drawPlayerHeadWithRoundedShader(ctx.getMatrices(), skin,
              headX, headY, headSize,
              BorderRadius.all(6F), ColorRGBA.WHITE.withAlpha(255 * fade));

      if (isHurt) {
         ctx.getMatrices().pop();
      }

      updateParticles();
      renderParticles(ctx, ctx.getMatrices(), fade);

      // --- ИМЯ ЦЕЛИ ---
      String name = (target == mc.player && NameProtect.INSTANCE.isEnabled())
              ? NameProtect.getCustomName()
              : target.getNameForScoreboard();

      MsdfRenderer.renderText(Fonts.BOLD, name, 9F,
              new ColorRGBA(0, 0, 0, 100 * fade).getRGB(),
              ctx.getMatrices().peek().getPositionMatrix(),
              contentX + 1, contentY + 1F, 0F, true, 0.7F, 1F, contentWidth);
      MsdfRenderer.renderText(Fonts.BOLD, name, 9F,
              ColorRGBA.WHITE.withAlpha(255 * fade).getRGB(),
              ctx.getMatrices().peek().getPositionMatrix(),
              contentX, contentY, 0F, true, 0.7F, 1F, contentWidth);

      // --- РАССТОЯНИЕ ---
      if (mc.player != null) {
         float dist = mc.player.distanceTo(target);
         String distText = String.format(Locale.US, "%.1f м", dist);
         MsdfRenderer.renderText(Fonts.REGULAR, distText, 7F,
                 new ColorRGBA(180, 180, 180, 200 * fade).getRGB(),
                 ctx.getMatrices().peek().getPositionMatrix(),
                 contentX, contentY + 10F, 0F, true, 0.7F, 1F, contentWidth);
      }

      // --- ПОЛОСКА ЗДОРОВЬЯ ---
      float maxHealth = target.getMaxHealth();
      float health = ScoreboardHealth.INSTANCE.isEnabled()
              ? PlayerIntersectionUtil.getHealth(target)
              : target.getHealth();
      float healthPercentCurrent = health / maxHealth;
      float absorptionPercent = target.getAbsorptionAmount() / maxHealth;

      healthAnimation.update(healthPercentCurrent);
      absorptionAnimation.update(absorptionPercent);

      if (lagHealthAnimation.getValue() > healthPercentCurrent) {
         lagHealthAnimation.update(healthPercentCurrent);
      } else {
         lagHealthAnimation.setValue(healthPercentCurrent);
      }

      float barY = y + HEIGHT - PADDING - BAR_HEIGHT;

      DrawUtil.drawRoundedRect(ctx.getMatrices(), contentX, barY, contentWidth, BAR_HEIGHT,
              BorderRadius.all(BAR_RADIUS), new ColorRGBA(20, 20, 20, 255 * fade));

      float lagWidth = contentWidth * lagHealthAnimation.getValue();
      if (lagWidth > 0) {
         DrawUtil.drawRoundedRect(ctx.getMatrices(), contentX, barY, lagWidth, BAR_HEIGHT,
                 BorderRadius.all(BAR_RADIUS), new ColorRGBA(150, 50, 50, 150 * fade));
      }

      float healthWidth = contentWidth * healthAnimation.getValue();
      if (healthWidth > 0) {
         ColorRGBA healthColor1 = interpolateColorGradient(healthPercentCurrent);
         ColorRGBA healthColor2 = healthColor1.darker(0.8F);
         DrawUtil.drawRoundedRect(ctx.getMatrices(), contentX, barY, healthWidth, BAR_HEIGHT,
                 BorderRadius.all(BAR_RADIUS),
                 healthColor1.withAlpha(255 * fade), healthColor1.withAlpha(255 * fade),
                 healthColor2.withAlpha(255 * fade), healthColor2.withAlpha(255 * fade));
      }

      hpPulseAnimation.update(healthPercentCurrent < 0.2F);
      float pulseGlow = hpPulseAnimation.getValue() * 0.3F;
      if (healthPercentCurrent < 0.2F) {
         DrawUtil.drawRoundedRect(ctx.getMatrices(),
                 contentX - 1, barY - 1, healthWidth + 2, BAR_HEIGHT + 2,
                 BorderRadius.all(BAR_RADIUS + 1),
                 new ColorRGBA(255, 50, 50, (int)(80 * fade * pulseGlow)));
      }

      float absorptionWidth = contentWidth * absorptionAnimation.getValue();
      if (absorptionWidth > 0) {
         float sparkle = (MathHelper.sin(mc.player.age * 0.3F) * 0.5F + 0.5F) * 0.5F + 0.5F;
         DrawUtil.drawRoundedRect(ctx.getMatrices(),
                 contentX, barY - 1.5F, absorptionWidth, 2.5F,
                 BorderRadius.all(1.5F),
                 new ColorRGBA(255, 215, 0, (int)(200 * fade * sparkle)));
      }

      // --- ТЕКСТ HP — СПРАВА НАД ПОЛОСКОЙ ---
      String hpText = String.format(Locale.US, "%.0f", health);
      float hpFontSize = 6F;
      float hpWidth = Fonts.REGULAR.getFont(hpFontSize).width(hpText);
      float hpX = contentX + contentWidth - hpWidth - 2F;
      float hpY = barY - 8F;

      ctx.drawText(Fonts.REGULAR.getFont(hpFontSize), hpText,
              hpX + 1, hpY + 1,
              new ColorRGBA(0, 0, 0, 100 * fade));
      ctx.drawText(Fonts.REGULAR.getFont(hpFontSize), hpText,
              hpX, hpY,
              ColorRGBA.WHITE.withAlpha(230 * fade));

      // --- БРОНЯ ---
      if (target instanceof PlayerEntity) {
         renderArmorAndItems(ctx, (PlayerEntity) target, x, y + HEIGHT + 4F, WIDTH, fade);
      }

      this.width = WIDTH;
      this.height = HEIGHT;
   }

   // ========== ЦВЕТ ЗДОРОВЬЯ ==========
   private ColorRGBA interpolateColorGradient(float percent) {
      if (percent > 0.8F) return new ColorRGBA(50, 255, 50);
      if (percent > 0.5F) return new ColorRGBA(255, 255, 50);
      if (percent > 0.2F) return new ColorRGBA(255, 150, 50);
      return new ColorRGBA(255, 50, 50);
   }

   // ========== ЧАСТИЦЫ УРОНА ==========
   private void spawnDamageParticles(float centerX, float centerY, ColorRGBA themeColor) {
      ColorRGBA baseColor = themeColor.mix(ColorRGBA.RED, 0.5F);

      for (int i = 0; i < PARTICLE_COUNT_PER_HURT; i++) {
         float angle = RANDOM.nextFloat() * (float) Math.PI * 2;
         float speed = PARTICLE_SPEED * (0.7F + RANDOM.nextFloat() * 0.6F);
         float vx = (float) Math.cos(angle) * speed;
         float vy = (float) Math.sin(angle) * speed - 0.5F;

         int lifetime = PARTICLE_LIFETIME + RANDOM.nextInt(6) - 3;
         float variation = 0.8F + RANDOM.nextFloat() * 0.4F;

         int r = (int) MathHelper.clamp(baseColor.getRed() * variation, 0, 255);
         int g = (int) MathHelper.clamp(baseColor.getGreen() * variation, 0, 255);
         int b = (int) MathHelper.clamp(baseColor.getBlue() * variation, 0, 255);
         int a = baseColor.getAlpha();

         ColorRGBA particleColor = new ColorRGBA(r, g, b, a);
         particles.add(new Particle(centerX, centerY, vx, vy, lifetime, particleColor));
      }
   }

   private void updateParticles() {
      particles.removeIf(p -> {
         p.update();
         return !p.isAlive();
      });
   }

   private void renderParticles(CustomDrawContext ctx, MatrixStack matrices, float fade) {
      if (particles.isEmpty()) return;

      RenderSystem.enableBlend();
      RenderSystem.defaultBlendFunc();
      RenderSystem.disableDepthTest();
      RenderSystem.depthMask(false);
      RenderSystem.setShader(ShaderProgramKeys.POSITION_COLOR);

      Matrix4f matrix = matrices.peek().getPositionMatrix();
      BufferBuilder buffer = Tessellator.getInstance().begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR);

      for (Particle p : particles) {
         float alpha = (float) p.life / p.maxLife * fade;
         int a = (int) (alpha * 255);
         int color = p.color.withAlpha(a).getRGB();

         float size = 1.5F + (1.0F - (float) p.life / p.maxLife) * 1.0F;
         float x1 = p.x - size;
         float y1 = p.y - size;
         float x2 = p.x + size;
         float y2 = p.y + size;

         int r = (color >> 16) & 0xFF;
         int g = (color >> 8) & 0xFF;
         int b = color & 0xFF;
         int a2 = (color >> 24) & 0xFF;

         buffer.vertex(matrix, x1, y2, 0).color(r, g, b, a2);
         buffer.vertex(matrix, x2, y2, 0).color(r, g, b, a2);
         buffer.vertex(matrix, x2, y1, 0).color(r, g, b, a2);
         buffer.vertex(matrix, x1, y1, 0).color(r, g, b, a2);
      }

      BufferRenderer.drawWithGlobalProgram(buffer.end());

      RenderSystem.enableDepthTest();
      RenderSystem.depthMask(true);
      RenderSystem.disableBlend();
   }

   // ========== БРОНЯ И ПРЕДМЕТЫ ==========
   private void renderArmorAndItems(CustomDrawContext ctx, PlayerEntity player, float baseX, float baseY, float hudWidth, float fade) {
      List<ItemStack> armor = player.getInventory().armor;
      ItemStack[] items = {
              player.getMainHandStack(),
              player.getOffHandStack(),
              armor.get(3),
              armor.get(2),
              armor.get(1),
              armor.get(0)
      };

      int count = 0;
      for (ItemStack stack : items) if (!stack.isEmpty()) count++;
      if (count == 0) return;

      float totalWidth = count * ARMOR_ICON_SIZE;
      float startX = baseX + (hudWidth - totalWidth) / 2F;
      float currentX = startX;

      DrawUtil.drawRoundedRect(ctx.getMatrices(),
              startX - 3, baseY - 2,
              totalWidth + 6, ARMOR_ICON_SIZE + 4,
              BorderRadius.all(4F),
              new ColorRGBA(20, 20, 20, 150 * fade));

      itemSpinAnimation.update(true);
      float spin = itemSpinAnimation.getValue();

      for (ItemStack stack : items) {
         if (!stack.isEmpty()) {
            ctx.getMatrices().push();
            ctx.getMatrices().translate(
                    currentX + ARMOR_ICON_SIZE / 2F,
                    baseY + ARMOR_ICON_SIZE / 2F,
                    0);
            ctx.getMatrices().multiply(RotationAxis.POSITIVE_Z.rotationDegrees(360 * (1 - spin)));
            ctx.getMatrices().scale(ARMOR_SCALE * (0.9F + 0.1F * spin),
                    ARMOR_SCALE * (0.9F + 0.1F * spin),
                    1);
            ctx.getMatrices().translate(-8, -8, 0);
            ctx.drawItem(stack, 0, 0);
            ((DrawContextAccessor) ctx).callDrawItemBar(stack, 0, 0);
            ctx.getMatrices().pop();
            currentX += ARMOR_ICON_SIZE;
         }
      }
   }

   // ========== ЭФФЕКТЫ ==========

   private String formatEffectTime(int ticks) {
      int seconds = ticks / 20;
      int minutes = seconds / 60;
      seconds %= 60;
      return String.format(Locale.US, "%d:%02d", minutes, seconds);
   }

   // ========== КЕШИРОВАНИЕ СКИНОВ ==========
   private Identifier getSkinTexture(LivingEntity entity) {
      if (!(entity instanceof PlayerEntity)) {
         return DefaultSkinHelper.getSteve().texture();
      }
      UUID uuid = entity.getUuid();
      if (skinCache.containsKey(uuid)) {
         return skinCache.get(uuid);
      }

      Identifier skin = DefaultSkinHelper.getSteve().texture();
      if (mc.getNetworkHandler() != null) {
         for (PlayerListEntry entry : mc.getNetworkHandler().getPlayerList()) {
            if (entry.getProfile().getId().equals(uuid)) {
               skin = entry.getSkinTextures().texture();
               break;
            }
         }
      }
      skinCache.put(uuid, skin);
      return skin;
   }

   public void setTarget(LivingEntity target) {
      this.target = target;
   }

   // ========== КЛАСС ЧАСТИЦЫ ==========
   private static class Particle {
      float x, y;
      float vx, vy;
      int life;
      int maxLife;
      ColorRGBA color;

      Particle(float x, float y, float vx, float vy, int maxLife, ColorRGBA color) {
         this.x = x;
         this.y = y;
         this.vx = vx;
         this.vy = vy;
         this.maxLife = maxLife;
         this.life = maxLife;
         this.color = color;
      }

      boolean isAlive() {
         return life > 0;
      }

      void update() {
         x += vx;
         y += vy;
         vy += 0.05F;
         life--;
      }
   }
}
Это пиздец
1771061221387.png
 
Назад
Сверху Снизу