- Выберите загрузчик игры
- Forge
- NeoForge
- ForgeOptiFine
SS Снизу
Короче вроде норм, но через нейронку
Короче вроде норм, но через нейронку
TargetHudComponent:
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--;
}
}
}