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

Визуальная часть Dynamic Island | Zenith no recode 1.21.4

Начинающий
Начинающий
Статус
Онлайн
Регистрация
29 Июл 2025
Сообщения
460
Реакции
16
Выберите загрузчик игры
  1. Fabric
Пожалуйста, авторизуйтесь для просмотра ссылки.

DynamicIsland:
Expand Collapse Copy
package ru.flow.client.screens.widgets;

import lombok.Getter;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.hud.BossBarHud;
import net.minecraft.client.gui.hud.ClientBossBar;
import net.minecraft.client.gui.hud.InGameHud;
import net.minecraft.client.network.PlayerListEntry;
import net.minecraft.client.texture.AbstractTexture;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.Nullable;
import ru.flow.api.client.widget.AbstractWidget;
import ru.flow.api.media.MediaUtils;
import ru.flow.api.system.animation.Direction;
import ru.flow.api.system.animation.Easing;
import ru.flow.api.system.animation.implement.WaveAnimation;
import ru.flow.base.GlobalRefs;
import ru.flow.base.utils.font.Font;
import ru.flow.base.utils.font.FontsContext;
import ru.flow.base.utils.shape.states.ColorState;
import ru.flow.base.utils.shape.states.RadiusState;
import ru.flow.client.modules.render.Interface;

import java.awt.*;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Getter
public class DynamicIsland extends AbstractWidget implements GlobalRefs {

    private static final long DISPLAY_MS = 2000L;
    private static final Color COLOR_GREEN = new Color(0xFF46FF00, true);
    private static final Color COLOR_RED = new Color(0xFFFF4242, true);
    private static final Color COLOR_DEFAULT = new Color(0xFFA442FF, true);

    private static volatile String currentLabel = "Mytheria";
    private static volatile Color currentStatusColor = COLOR_DEFAULT;
    private static volatile NotificationType currentNotificationType = NotificationType.DEFAULT;
    private static volatile long resetAt = 0L;

    private final WaveAnimation[] waveAnimations = new WaveAnimation[4];
    private final SimpleAnimation widthAnimation, heightAnimation;

    public DynamicIsland() {
        super("DynamicIsland", 10, 10, 128, 15, true);
        widthAnimation = new SimpleAnimation(0f, 30);
        heightAnimation = new SimpleAnimation(0f, 30);

        for (int i = 0; i < 4; i++) {
            waveAnimations[i] = new WaveAnimation(450 + (int)(Math.random() * 250), 10, Easing.BOTH_SINE);
        }
    }

    public static void addNotification(String text, NotificationType type) {
        currentLabel = text;
        currentNotificationType = type;
        currentStatusColor = type.color;
        resetAt = System.currentTimeMillis() + DISPLAY_MS;
    }

    public static void notifyModuleToggle(String moduleName, boolean enabled) {
        addNotification(moduleName + (enabled ? " включен" : " выключен"),
                enabled ? NotificationType.SUCCESS : NotificationType.ERROR);
    }

    public static void strengthNotification() {
        if (mc.player == null) return;
        float criticalThreshold = 0.1f;

        ItemStack[] armorSlots = {
                mc.player.getEquippedStack(EquipmentSlot.FEET),
                mc.player.getEquippedStack(EquipmentSlot.LEGS),
                mc.player.getEquippedStack(EquipmentSlot.CHEST),
                mc.player.getEquippedStack(EquipmentSlot.HEAD)
        };

        String[] slotNames = {"Ботинки", "Поножи", "Нагрудник", "Шлем"};

        for (int i = 0; i < armorSlots.length; i++) {
            ItemStack armor = armorSlots[i];
            if (armor.isEmpty() || !armor.isDamageable()) continue;

            int maxDurability = armor.getMaxDamage();
            int currentDamage = armor.getDamage();
            int durabilityLeft = maxDurability - currentDamage;
            float durabilityPercent = (float) durabilityLeft / maxDurability;

            if (durabilityPercent <= criticalThreshold && durabilityPercent > 0) {
                addNotification(slotNames[i] + " имеет низкую прочность!", NotificationType.WARNING);
                return;
            }
        }
    }

    @Override
    public void drawWidget(DrawContext context) {
        renderWatermark(context.getMatrices(), context.getScaledWindowWidth());
    }

    private void renderWatermark(MatrixStack ms, int screenWidth) {
        if (resetAt != 0L && System.currentTimeMillis() >= resetAt) {
            currentLabel = "Mytheria";
            currentStatusColor = COLOR_DEFAULT;
            currentNotificationType = NotificationType.DEFAULT;
            resetAt = 0L;
        }

        RenderContext ctx = new RenderContext(screenWidth);
        WatermarkContent content = determineContent();

        animateDimensions(content);

        float w = widthAnimation.getOutput();
        float h = heightAnimation.getOutput();
        float x = screenWidth / 2f - (w + ctx.timeWidth + 6f) / 2f + ctx.timeWidth - 6f;
        float y = 7f;

        renderTime(ms, ctx, x, y, h);
        renderBackground(ms, x, y, w, h);
        renderContent(ms, content, x, y, w, h);
        renderConnectionIndicator(ms, ctx, x, y, w, h);
    }

    private WatermarkContent determineContent() {
        if (System.currentTimeMillis() < resetAt) {
            return createNotificationContent();
        }

        ClientBossBar bossBar = getPrimaryBossBar();
        if (bossBar != null) return createBossBarContent(bossBar);

        MediaUtils.MediaInfo media = MediaUtils.getCurrentMedia();
        if (media != null && media.getTexture() != null) return createMediaContent(media);

        return createDefaultContent();
    }

    private WatermarkContent createNotificationContent() {
        Font font = FontsContext.REGULAR.getFont(9f);
        float labelW = font.getFont().getWidth(currentLabel, 9f);
        return new WatermarkContent(ContentType.NOTIFICATION, 11f + 3f + labelW + 7.5f,
                Math.max(11f, 11f), currentLabel, false);
    }

    private WatermarkContent createBossBarContent(ClientBossBar bar) {
        float[] size = calculateBossBarSize(bar);
        return new WatermarkContent(ContentType.BOSS_BAR, size[0], size[1], bar, true);
    }

    private WatermarkContent createMediaContent(MediaUtils.MediaInfo media) {
        Font font = FontsContext.REGULAR.getFont(9f);
        float trackW = font.getFont().getWidth(media.title, 9f);
        float waveW = 4 * 2.5f + 3 * 1f + 2f;
        return new WatermarkContent(ContentType.MEDIA, 11f + 4f + trackW + 3f + waveW,
                Math.max(11f, 11f), media, false);
    }

    private WatermarkContent createDefaultContent() {
        Font font = FontsContext.REGULAR.getFont(9f);
        float labelW = font.getFont().getWidth(currentLabel, 9f);
        return new WatermarkContent(ContentType.DEFAULT, 11f + 4f + labelW + 2,
                Math.max(11f, 11f), currentLabel, false);
    }

    private void renderContent(MatrixStack ms, WatermarkContent content, float x, float y, float w, float h) {
        float cx = x + 6f;
        float cy = y + (h - content.height) / 2f;

        switch (content.type) {
            case NOTIFICATION:
                renderStatusBox(ms, cx, cy, content.height, currentStatusColor);
                renderLabel(ms, currentLabel, cx + 13f, cy, content.height);
                break;
            case BOSS_BAR:
                renderBossBar(ms, (ClientBossBar) content.data, cx + 2f, cy + 15f, content.width, 2f);
                break;
            case MEDIA:
                renderMediaInfo(ms, (MediaUtils.MediaInfo) content.data, cx, cy, content.height);
                break;
            case DEFAULT:
                renderStatusBox(ms, cx, cy, content.height, currentStatusColor);
                renderLabel(ms, currentLabel, cx + 14f, cy, content.height);
                break;
        }
    }

    private void renderMediaInfo(MatrixStack ms, MediaUtils.MediaInfo media, float x, float y, float h) {
        float size = 14f;
        ru.flow.base.utils.render.RenderContext.drawTexture(ms, x - 3.5f, y + (h - size) / 2f - 1f,
                size, size, 5.5f, media.getTexture(), Color.WHITE);

        renderLabel(ms, media.title, x + 14f, y, h);
        renderWaveAnimation(ms, x, y, h, media);
    }

    private void renderWaveAnimation(MatrixStack ms, float baseX, float baseY, float h, MediaUtils.MediaInfo media) {
        Font font = FontsContext.REGULAR.getFont(9f);
        float trackW = font.getFont().getWidth(media.title, 9f);
        float textEndX = baseX + 11f + 4f + trackW + 4f;
        float groupW = 4 * (2.5f + 1f) - 1f;
        float centerX = textEndX + groupW / 2f;
        float waveY = baseY + h + 5f;

        for (WaveAnimation anim : waveAnimations) {
            if (anim.isFinished(anim.getDirection())) {
                if (anim.getDirection() == Direction.FORWARDS) {
                    anim.setDirection(Direction.BACKWARDS);
                } else {
                    anim.setValue(4 + Math.random() * 2);
                    anim.setMs(350 + (int)(Math.random() * 400));
                    anim.setDirection(Direction.FORWARDS);
                }
            }
        }

        Color waveColor = desaturate(MediaUtils.lastAlbumColor, 0.5f);
        for (int i = 0; i < 4; i++) {
            double half = waveAnimations[i].getOutput();
            float barX = centerX + (i - 2f) * 3.5f;
            ru.flow.base.utils.render.RenderContext.drawRound(barX + 3, waveY - (float)half - 11,
                    2.3f, (float)(half * 2), 0.7f, waveColor, ms);
        }
    }

    private void renderTime(MatrixStack ms, RenderContext ctx, float x, float y, float h) {
        float timeX = x - ctx.timeWidth - 6f;
        float timeY = y + (h - 9f) / 2f + 1f;
        ru.flow.base.utils.render.RenderContext.drawText(FontsContext.MEDIUM.getFont(9f),
                ctx.timeString, timeX - 3, timeY, ctx.timeColor.getRGB(), ms.peek().getPositionMatrix());
    }

    private void renderBackground(MatrixStack ms, float x, float y, float w, float h) {
        MediaUtils.MediaInfo media = MediaUtils.getCurrentMedia();
        Color bg = media != null && media.getTexture() != null
                ? desaturate(MediaUtils.lastAlbumColor, 0.5f)
                : new Color(0xFF464646, true);
        float blur = media != null && media.getTexture() != null ? 55f : 25f;

        ru.flow.base.utils.render.RenderContext.drawBlur(ms, x, y, w - 8, h - 2,
                new ColorState(bg), new RadiusState(8.5), 1f, blur);
    }

    private void renderStatusBox(MatrixStack ms, float x, float y, float h, Color color) {

        ru.flow.base.utils.render.RenderContext.drawRound(x - 1.5f, y + (h - 11f) / 2f - 1,
                11f, 11f, 4.5f, color, ms);
    }

    private void renderLabel(MatrixStack ms, String text, float x, float y, float h) {
        ru.flow.base.utils.render.RenderContext.drawText(FontsContext.MEDIUM.getFont(9f),
                text, x, y - 1f + (h - 9f) / 2f + 1.25f, Color.WHITE.getRGB(), ms.peek().getPositionMatrix());
    }

    private void renderBossBar(MatrixStack ms, ClientBossBar bar, float x, float y, float w, float h) {
        BossBarInfo info = extractBossBarInfo(bar);
        float timeBoxW = info.timeWidth + 10f;
        float totalW = timeBoxW + info.labelWidth;
        float cx = x + (w - totalW) / 2f;
        float ty = y - 9f - 4f;

        ru.flow.base.utils.render.RenderContext.drawRound(cx -5.5f, ty - 2f, timeBoxW, 11.5f, 3, COLOR_RED, ms);
        ru.flow.base.utils.render.RenderContext.drawText(FontsContext.MEDIUM.getFont(9f),
                info.timeString, cx - 1, ty, Color.WHITE.getRGB(), ms.peek().getPositionMatrix());
        ru.flow.base.utils.render.RenderContext.drawText(FontsContext.MEDIUM.getFont(9f),
                info.labelText, cx + timeBoxW - 3, ty, Color.WHITE.getRGB(), ms.peek().getPositionMatrix());
    }

    private void renderConnectionIndicator(MatrixStack ms, RenderContext ctx, float x, float y, float w, float h) {
        float ix = x + w;
        float iy = y + (h - 9f) / 2f - 3f;

        if (Interface.getInstance().conIcon.isSelected("Обычная")) {
            String symbol = mc.isInSingleplayer() ? "A" : "B";
            ru.flow.base.utils.render.RenderContext.drawText(FontsContext.ICF.getFont(12f),
                    symbol, ix, iy + 1.5f, ctx.timeColor.getRGB(), ms.peek().getPositionMatrix());
        } else if (Interface.getInstance().conIcon.isSelected("Продвинутая")) {
            if (mc.isInSingleplayer()) {
                ru.flow.base.utils.render.RenderContext.drawText(FontsContext.ICF.getFont(12f),
                        "A", ix, iy + 1.5f, ctx.timeColor.getRGB(), ms.peek().getPositionMatrix());
            } else {
                renderConnectionQuality(ms, ix, iy + 2f);
            }
        }
    }

    private void renderConnectionQuality(MatrixStack ms, float x, float y) {
        int ping = getPlayerPing();
        int white = ping <= 60 ? 4 : ping <= 80 ? 3 : ping <= 100 ? 2 : ping <= 120 ? 1 : 0;
        int[] heights = {4, 6, 8, 10};

        for (int i = 0; i < 4; i++) {
            Color c = i < white ? new Color(0xDDFFFFFF, true) : new Color(0x3DFFFFFF, true);
            float bh = heights[i];
            ru.flow.base.utils.render.RenderContext.drawRound(x + i * 3.3f, y + (10 - bh),
                    3f, bh, 0.2f, c, ms);
        }
    }

    private void animateDimensions(WatermarkContent content) {
        float w = content.width + 20f;
        float h = Math.max(20f, content.height + 8f);
        if (content.needsExtraHeight) h -= 1f;

        if (Math.abs(widthAnimation.getOutput() - w) > 0.5f) widthAnimation.animateTo(w);
        if (Math.abs(heightAnimation.getOutput() - h) > 0.5f) heightAnimation.animateTo(h);
    }

    private @Nullable ClientBossBar getPrimaryBossBar() {
        InGameHud hud = mc.inGameHud;
        BossBarHud bossBarHud = hud.getBossBarHud();
        Map<UUID, ClientBossBar> bars = bossBarHud.bossBars;
        return bars.isEmpty() ? null : bars.values().iterator().next();
    }


    private int getPlayerPing() {
        if (mc.player == null || mc.getNetworkHandler() == null) return 0;
        PlayerListEntry entry = mc.getNetworkHandler().getPlayerListEntry(mc.player.getUuid());
        return entry != null ? entry.getLatency() : 0;
    }

    private BossBarInfo extractBossBarInfo(ClientBossBar bar) {
        String raw = bar.getName().getString();
        Font font = FontsContext.REGULAR.getFont(9f);

        Pattern pattern = Pattern.compile("(\\d+)(?!.*\\d)");
        Matcher matcher = pattern.matcher(raw);
        String time = matcher.find() ? matcher.group(1) + "s" : "??s";

        String label = raw.replaceAll(",?\\s*до конца.*$", "")
                .replaceAll("Телепортация.*", "Телепортация").trim();

        return new BossBarInfo(time, label,
                font.getFont().getWidth(time, 9f),
                font.getFont().getWidth(label, 9f));
    }

    private float[] calculateBossBarSize(ClientBossBar bar) {
        BossBarInfo info = extractBossBarInfo(bar);
        return new float[] { info.timeWidth + 16f + info.labelWidth, 13f };
    }

    private Color desaturate(Color c, float factor) {
        float[] hsb = Color.RGBtoHSB(c.getRed(), c.getGreen(), c.getBlue(), null);
        hsb[1] *= factor;
        return new Color(Color.HSBtoRGB(hsb[0], hsb[1], hsb[2]));
    }

    public enum NotificationType {
        SUCCESS(new Color(0xFF46FF00, true)),
        ERROR(new Color(0xFFFF4242, true)),
        WARNING(new Color(0xFFFFAA00, true)),
        INFO(new Color(0xFF42A5FF, true)),
        DEFAULT(new Color(0xFFA442FF, true));

        public final Color color;
        NotificationType(Color color) { this.color = color; }
    }

    private enum ContentType { NOTIFICATION, BOSS_BAR, MEDIA, DEFAULT }

    private static class WatermarkContent {
        final ContentType type;
        final float width, height;
        final Object data;
        final boolean needsExtraHeight;

        WatermarkContent(ContentType type, float width, float height, Object data, boolean needsExtraHeight) {
            this.type = type;
            this.width = width;
            this.height = height;
            this.data = data;
            this.needsExtraHeight = needsExtraHeight;
        }
    }

    private static class RenderContext {
        final String timeString;
        final float timeWidth;
        final Color timeColor;

        RenderContext(int screenWidth) {
            Font font = FontsContext.REGULAR.getFont(9f);
            timeString = LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm"));
            timeWidth = font.getFont().getWidth(timeString, 9f);
            timeColor = Color.WHITE;
        }
    }

    private static class BossBarInfo {
        final String timeString, labelText;
        final float timeWidth, labelWidth;

        BossBarInfo(String timeString, String labelText, float timeWidth, float labelWidth) {
            this.timeString = timeString;
            this.labelText = labelText;
            this.timeWidth = timeWidth;
            this.labelWidth = labelWidth;
        }
    }

    private static class SimpleAnimation {
        private float current, target;
        private final long duration;
        private long start;
        private boolean running;

        SimpleAnimation(float val, long duration) {
            this.current = this.target = val;
            this.duration = duration;
        }

        void animateTo(float newTarget) {
            target = newTarget;
            start = System.currentTimeMillis();
            running = true;
        }

        float getOutput() {
            if (!running) return current;

            long elapsed = System.currentTimeMillis() - start;
            float progress = Math.min(1f, (float) elapsed / duration);
            current = current + progress * (target - current);

            if (progress >= 1f) {
                running = false;
                current = target;
            }
            return current;
        }
    }
}
MediaUtils:
Expand Collapse Copy
package ru.flow.api.media;

import by.bonenaut7.mediatransport4j.api.MediaSession;
import by.bonenaut7.mediatransport4j.api.MediaTransport;
import com.google.common.io.BaseEncoding;
import net.minecraft.client.texture.AbstractTexture;
import ru.flow.base.utils.render.Render2DUtil;
import ru.flow.base.utils.render.RenderContext;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.nio.ByteBuffer;
import java.security.MessageDigest;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class MediaUtils {

    private static boolean initialized = false;
    private static final ScheduledExecutorService s = Executors.newSingleThreadScheduledExecutor();
    private static volatile MediaInfo mediaInfo = null;
    public static volatile Color lastAlbumColor = Color.WHITE;

    private static final Map<String, AbstractTexture> textureCache = new ConcurrentHashMap<>();
    private static String previousHash = "";

    public static class MediaInfo {
        public final String title;
        public final String artist;
        public final String textureHash;

        public MediaInfo(String title, String artist, String textureHash) {
            this.title = title;
            this.artist = artist;
            this.textureHash = textureHash;
        }

        public AbstractTexture getTexture() {
            return textureCache.get(textureHash);
        }
    }

    public static MediaInfo getCurrentMedia() {
        if (!initialized) {
            boolean bb = MediaTransport.init();
            initialized = true;
            s.scheduleAtFixedRate(() -> {
                try {
                    List<MediaSession> sessions = MediaTransport.getMediaSessions();
                    if (sessions != null && !sessions.isEmpty()) {
                        final MediaSession mediaSession = sessions.get(0);

                        String hash = "";
                        AbstractTexture texture = null;

                        if (mediaSession.hasThumbnail()) {
                            ByteBuffer buf = mediaSession.getThumbnail();
                            hash = hashBuffer(buf);

                            if (!hash.equals(previousHash)) {
                                AbstractTexture old = textureCache.remove(previousHash);
                                if (old != null) old.close();

                                texture = convertTexture(buf);
                                if (texture != null) {
                                    textureCache.put(hash, texture);
                                }
                                previousHash = hash;
                            }
                        }

                        mediaInfo = new MediaInfo(mediaSession.getTitle(), mediaSession.getArtist(), hash);
                    } else {
                        clearCache();
                        mediaInfo = null;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }, 0, 50, TimeUnit.MILLISECONDS);
        }
        return mediaInfo;
    }

    public static Color getAverageColor(BufferedImage img) {
        long r = 0, g = 0, b = 0;
        int count = 0;

        int step = 5;
        for (int x = 0; x < img.getWidth(); x += step) {
            for (int y = 0; y < img.getHeight(); y += step) {
                int rgb = img.getRGB(x, y);
                r += (rgb >> 16) & 0xFF;
                g += (rgb >> 8) & 0xFF;
                b += (rgb) & 0xFF;
                count++;
            }
        }

        if (count == 0) return new Color(255, 255, 255);
        return new Color((int)(r / count), (int)(g / count), (int)(b / count));
    }

    private static AbstractTexture convertTexture(ByteBuffer buffer) {
        try {
            BufferedImage img = ImageIO.read(new ByteArrayInputStream(buffer.array()));
            if (img != null) {
                lastAlbumColor = getAverageColor(img);
                return RenderContext.convert(img);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }



    private static String hashBuffer(ByteBuffer buffer) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(buffer.array());
            return BaseEncoding.base16().lowerCase().encode(md.digest());
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    private static void clearCache() {
        textureCache.values().forEach(AbstractTexture::close);
        textureCache.clear();
        previousHash = "";
    }
}
 
Пожалуйста, авторизуйтесь для просмотра ссылки.

DynamicIsland:
Expand Collapse Copy
package ru.flow.client.screens.widgets;

import lombok.Getter;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.hud.BossBarHud;
import net.minecraft.client.gui.hud.ClientBossBar;
import net.minecraft.client.gui.hud.InGameHud;
import net.minecraft.client.network.PlayerListEntry;
import net.minecraft.client.texture.AbstractTexture;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.Nullable;
import ru.flow.api.client.widget.AbstractWidget;
import ru.flow.api.media.MediaUtils;
import ru.flow.api.system.animation.Direction;
import ru.flow.api.system.animation.Easing;
import ru.flow.api.system.animation.implement.WaveAnimation;
import ru.flow.base.GlobalRefs;
import ru.flow.base.utils.font.Font;
import ru.flow.base.utils.font.FontsContext;
import ru.flow.base.utils.shape.states.ColorState;
import ru.flow.base.utils.shape.states.RadiusState;
import ru.flow.client.modules.render.Interface;

import java.awt.*;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Getter
public class DynamicIsland extends AbstractWidget implements GlobalRefs {

    private static final long DISPLAY_MS = 2000L;
    private static final Color COLOR_GREEN = new Color(0xFF46FF00, true);
    private static final Color COLOR_RED = new Color(0xFFFF4242, true);
    private static final Color COLOR_DEFAULT = new Color(0xFFA442FF, true);

    private static volatile String currentLabel = "Mytheria";
    private static volatile Color currentStatusColor = COLOR_DEFAULT;
    private static volatile NotificationType currentNotificationType = NotificationType.DEFAULT;
    private static volatile long resetAt = 0L;

    private final WaveAnimation[] waveAnimations = new WaveAnimation[4];
    private final SimpleAnimation widthAnimation, heightAnimation;

    public DynamicIsland() {
        super("DynamicIsland", 10, 10, 128, 15, true);
        widthAnimation = new SimpleAnimation(0f, 30);
        heightAnimation = new SimpleAnimation(0f, 30);

        for (int i = 0; i < 4; i++) {
            waveAnimations[i] = new WaveAnimation(450 + (int)(Math.random() * 250), 10, Easing.BOTH_SINE);
        }
    }

    public static void addNotification(String text, NotificationType type) {
        currentLabel = text;
        currentNotificationType = type;
        currentStatusColor = type.color;
        resetAt = System.currentTimeMillis() + DISPLAY_MS;
    }

    public static void notifyModuleToggle(String moduleName, boolean enabled) {
        addNotification(moduleName + (enabled ? " включен" : " выключен"),
                enabled ? NotificationType.SUCCESS : NotificationType.ERROR);
    }

    public static void strengthNotification() {
        if (mc.player == null) return;
        float criticalThreshold = 0.1f;

        ItemStack[] armorSlots = {
                mc.player.getEquippedStack(EquipmentSlot.FEET),
                mc.player.getEquippedStack(EquipmentSlot.LEGS),
                mc.player.getEquippedStack(EquipmentSlot.CHEST),
                mc.player.getEquippedStack(EquipmentSlot.HEAD)
        };

        String[] slotNames = {"Ботинки", "Поножи", "Нагрудник", "Шлем"};

        for (int i = 0; i < armorSlots.length; i++) {
            ItemStack armor = armorSlots[i];
            if (armor.isEmpty() || !armor.isDamageable()) continue;

            int maxDurability = armor.getMaxDamage();
            int currentDamage = armor.getDamage();
            int durabilityLeft = maxDurability - currentDamage;
            float durabilityPercent = (float) durabilityLeft / maxDurability;

            if (durabilityPercent <= criticalThreshold && durabilityPercent > 0) {
                addNotification(slotNames[i] + " имеет низкую прочность!", NotificationType.WARNING);
                return;
            }
        }
    }

    @Override
    public void drawWidget(DrawContext context) {
        renderWatermark(context.getMatrices(), context.getScaledWindowWidth());
    }

    private void renderWatermark(MatrixStack ms, int screenWidth) {
        if (resetAt != 0L && System.currentTimeMillis() >= resetAt) {
            currentLabel = "Mytheria";
            currentStatusColor = COLOR_DEFAULT;
            currentNotificationType = NotificationType.DEFAULT;
            resetAt = 0L;
        }

        RenderContext ctx = new RenderContext(screenWidth);
        WatermarkContent content = determineContent();

        animateDimensions(content);

        float w = widthAnimation.getOutput();
        float h = heightAnimation.getOutput();
        float x = screenWidth / 2f - (w + ctx.timeWidth + 6f) / 2f + ctx.timeWidth - 6f;
        float y = 7f;

        renderTime(ms, ctx, x, y, h);
        renderBackground(ms, x, y, w, h);
        renderContent(ms, content, x, y, w, h);
        renderConnectionIndicator(ms, ctx, x, y, w, h);
    }

    private WatermarkContent determineContent() {
        if (System.currentTimeMillis() < resetAt) {
            return createNotificationContent();
        }

        ClientBossBar bossBar = getPrimaryBossBar();
        if (bossBar != null) return createBossBarContent(bossBar);

        MediaUtils.MediaInfo media = MediaUtils.getCurrentMedia();
        if (media != null && media.getTexture() != null) return createMediaContent(media);

        return createDefaultContent();
    }

    private WatermarkContent createNotificationContent() {
        Font font = FontsContext.REGULAR.getFont(9f);
        float labelW = font.getFont().getWidth(currentLabel, 9f);
        return new WatermarkContent(ContentType.NOTIFICATION, 11f + 3f + labelW + 7.5f,
                Math.max(11f, 11f), currentLabel, false);
    }

    private WatermarkContent createBossBarContent(ClientBossBar bar) {
        float[] size = calculateBossBarSize(bar);
        return new WatermarkContent(ContentType.BOSS_BAR, size[0], size[1], bar, true);
    }

    private WatermarkContent createMediaContent(MediaUtils.MediaInfo media) {
        Font font = FontsContext.REGULAR.getFont(9f);
        float trackW = font.getFont().getWidth(media.title, 9f);
        float waveW = 4 * 2.5f + 3 * 1f + 2f;
        return new WatermarkContent(ContentType.MEDIA, 11f + 4f + trackW + 3f + waveW,
                Math.max(11f, 11f), media, false);
    }

    private WatermarkContent createDefaultContent() {
        Font font = FontsContext.REGULAR.getFont(9f);
        float labelW = font.getFont().getWidth(currentLabel, 9f);
        return new WatermarkContent(ContentType.DEFAULT, 11f + 4f + labelW + 2,
                Math.max(11f, 11f), currentLabel, false);
    }

    private void renderContent(MatrixStack ms, WatermarkContent content, float x, float y, float w, float h) {
        float cx = x + 6f;
        float cy = y + (h - content.height) / 2f;

        switch (content.type) {
            case NOTIFICATION:
                renderStatusBox(ms, cx, cy, content.height, currentStatusColor);
                renderLabel(ms, currentLabel, cx + 13f, cy, content.height);
                break;
            case BOSS_BAR:
                renderBossBar(ms, (ClientBossBar) content.data, cx + 2f, cy + 15f, content.width, 2f);
                break;
            case MEDIA:
                renderMediaInfo(ms, (MediaUtils.MediaInfo) content.data, cx, cy, content.height);
                break;
            case DEFAULT:
                renderStatusBox(ms, cx, cy, content.height, currentStatusColor);
                renderLabel(ms, currentLabel, cx + 14f, cy, content.height);
                break;
        }
    }

    private void renderMediaInfo(MatrixStack ms, MediaUtils.MediaInfo media, float x, float y, float h) {
        float size = 14f;
        ru.flow.base.utils.render.RenderContext.drawTexture(ms, x - 3.5f, y + (h - size) / 2f - 1f,
                size, size, 5.5f, media.getTexture(), Color.WHITE);

        renderLabel(ms, media.title, x + 14f, y, h);
        renderWaveAnimation(ms, x, y, h, media);
    }

    private void renderWaveAnimation(MatrixStack ms, float baseX, float baseY, float h, MediaUtils.MediaInfo media) {
        Font font = FontsContext.REGULAR.getFont(9f);
        float trackW = font.getFont().getWidth(media.title, 9f);
        float textEndX = baseX + 11f + 4f + trackW + 4f;
        float groupW = 4 * (2.5f + 1f) - 1f;
        float centerX = textEndX + groupW / 2f;
        float waveY = baseY + h + 5f;

        for (WaveAnimation anim : waveAnimations) {
            if (anim.isFinished(anim.getDirection())) {
                if (anim.getDirection() == Direction.FORWARDS) {
                    anim.setDirection(Direction.BACKWARDS);
                } else {
                    anim.setValue(4 + Math.random() * 2);
                    anim.setMs(350 + (int)(Math.random() * 400));
                    anim.setDirection(Direction.FORWARDS);
                }
            }
        }

        Color waveColor = desaturate(MediaUtils.lastAlbumColor, 0.5f);
        for (int i = 0; i < 4; i++) {
            double half = waveAnimations[i].getOutput();
            float barX = centerX + (i - 2f) * 3.5f;
            ru.flow.base.utils.render.RenderContext.drawRound(barX + 3, waveY - (float)half - 11,
                    2.3f, (float)(half * 2), 0.7f, waveColor, ms);
        }
    }

    private void renderTime(MatrixStack ms, RenderContext ctx, float x, float y, float h) {
        float timeX = x - ctx.timeWidth - 6f;
        float timeY = y + (h - 9f) / 2f + 1f;
        ru.flow.base.utils.render.RenderContext.drawText(FontsContext.MEDIUM.getFont(9f),
                ctx.timeString, timeX - 3, timeY, ctx.timeColor.getRGB(), ms.peek().getPositionMatrix());
    }

    private void renderBackground(MatrixStack ms, float x, float y, float w, float h) {
        MediaUtils.MediaInfo media = MediaUtils.getCurrentMedia();
        Color bg = media != null && media.getTexture() != null
                ? desaturate(MediaUtils.lastAlbumColor, 0.5f)
                : new Color(0xFF464646, true);
        float blur = media != null && media.getTexture() != null ? 55f : 25f;

        ru.flow.base.utils.render.RenderContext.drawBlur(ms, x, y, w - 8, h - 2,
                new ColorState(bg), new RadiusState(8.5), 1f, blur);
    }

    private void renderStatusBox(MatrixStack ms, float x, float y, float h, Color color) {

        ru.flow.base.utils.render.RenderContext.drawRound(x - 1.5f, y + (h - 11f) / 2f - 1,
                11f, 11f, 4.5f, color, ms);
    }

    private void renderLabel(MatrixStack ms, String text, float x, float y, float h) {
        ru.flow.base.utils.render.RenderContext.drawText(FontsContext.MEDIUM.getFont(9f),
                text, x, y - 1f + (h - 9f) / 2f + 1.25f, Color.WHITE.getRGB(), ms.peek().getPositionMatrix());
    }

    private void renderBossBar(MatrixStack ms, ClientBossBar bar, float x, float y, float w, float h) {
        BossBarInfo info = extractBossBarInfo(bar);
        float timeBoxW = info.timeWidth + 10f;
        float totalW = timeBoxW + info.labelWidth;
        float cx = x + (w - totalW) / 2f;
        float ty = y - 9f - 4f;

        ru.flow.base.utils.render.RenderContext.drawRound(cx -5.5f, ty - 2f, timeBoxW, 11.5f, 3, COLOR_RED, ms);
        ru.flow.base.utils.render.RenderContext.drawText(FontsContext.MEDIUM.getFont(9f),
                info.timeString, cx - 1, ty, Color.WHITE.getRGB(), ms.peek().getPositionMatrix());
        ru.flow.base.utils.render.RenderContext.drawText(FontsContext.MEDIUM.getFont(9f),
                info.labelText, cx + timeBoxW - 3, ty, Color.WHITE.getRGB(), ms.peek().getPositionMatrix());
    }

    private void renderConnectionIndicator(MatrixStack ms, RenderContext ctx, float x, float y, float w, float h) {
        float ix = x + w;
        float iy = y + (h - 9f) / 2f - 3f;

        if (Interface.getInstance().conIcon.isSelected("Обычная")) {
            String symbol = mc.isInSingleplayer() ? "A" : "B";
            ru.flow.base.utils.render.RenderContext.drawText(FontsContext.ICF.getFont(12f),
                    symbol, ix, iy + 1.5f, ctx.timeColor.getRGB(), ms.peek().getPositionMatrix());
        } else if (Interface.getInstance().conIcon.isSelected("Продвинутая")) {
            if (mc.isInSingleplayer()) {
                ru.flow.base.utils.render.RenderContext.drawText(FontsContext.ICF.getFont(12f),
                        "A", ix, iy + 1.5f, ctx.timeColor.getRGB(), ms.peek().getPositionMatrix());
            } else {
                renderConnectionQuality(ms, ix, iy + 2f);
            }
        }
    }

    private void renderConnectionQuality(MatrixStack ms, float x, float y) {
        int ping = getPlayerPing();
        int white = ping <= 60 ? 4 : ping <= 80 ? 3 : ping <= 100 ? 2 : ping <= 120 ? 1 : 0;
        int[] heights = {4, 6, 8, 10};

        for (int i = 0; i < 4; i++) {
            Color c = i < white ? new Color(0xDDFFFFFF, true) : new Color(0x3DFFFFFF, true);
            float bh = heights[i];
            ru.flow.base.utils.render.RenderContext.drawRound(x + i * 3.3f, y + (10 - bh),
                    3f, bh, 0.2f, c, ms);
        }
    }

    private void animateDimensions(WatermarkContent content) {
        float w = content.width + 20f;
        float h = Math.max(20f, content.height + 8f);
        if (content.needsExtraHeight) h -= 1f;

        if (Math.abs(widthAnimation.getOutput() - w) > 0.5f) widthAnimation.animateTo(w);
        if (Math.abs(heightAnimation.getOutput() - h) > 0.5f) heightAnimation.animateTo(h);
    }

    private @Nullable ClientBossBar getPrimaryBossBar() {
        InGameHud hud = mc.inGameHud;
        BossBarHud bossBarHud = hud.getBossBarHud();
        Map<UUID, ClientBossBar> bars = bossBarHud.bossBars;
        return bars.isEmpty() ? null : bars.values().iterator().next();
    }


    private int getPlayerPing() {
        if (mc.player == null || mc.getNetworkHandler() == null) return 0;
        PlayerListEntry entry = mc.getNetworkHandler().getPlayerListEntry(mc.player.getUuid());
        return entry != null ? entry.getLatency() : 0;
    }

    private BossBarInfo extractBossBarInfo(ClientBossBar bar) {
        String raw = bar.getName().getString();
        Font font = FontsContext.REGULAR.getFont(9f);

        Pattern pattern = Pattern.compile("(\\d+)(?!.*\\d)");
        Matcher matcher = pattern.matcher(raw);
        String time = matcher.find() ? matcher.group(1) + "s" : "??s";

        String label = raw.replaceAll(",?\\s*до конца.*$", "")
                .replaceAll("Телепортация.*", "Телепортация").trim();

        return new BossBarInfo(time, label,
                font.getFont().getWidth(time, 9f),
                font.getFont().getWidth(label, 9f));
    }

    private float[] calculateBossBarSize(ClientBossBar bar) {
        BossBarInfo info = extractBossBarInfo(bar);
        return new float[] { info.timeWidth + 16f + info.labelWidth, 13f };
    }

    private Color desaturate(Color c, float factor) {
        float[] hsb = Color.RGBtoHSB(c.getRed(), c.getGreen(), c.getBlue(), null);
        hsb[1] *= factor;
        return new Color(Color.HSBtoRGB(hsb[0], hsb[1], hsb[2]));
    }

    public enum NotificationType {
        SUCCESS(new Color(0xFF46FF00, true)),
        ERROR(new Color(0xFFFF4242, true)),
        WARNING(new Color(0xFFFFAA00, true)),
        INFO(new Color(0xFF42A5FF, true)),
        DEFAULT(new Color(0xFFA442FF, true));

        public final Color color;
        NotificationType(Color color) { this.color = color; }
    }

    private enum ContentType { NOTIFICATION, BOSS_BAR, MEDIA, DEFAULT }

    private static class WatermarkContent {
        final ContentType type;
        final float width, height;
        final Object data;
        final boolean needsExtraHeight;

        WatermarkContent(ContentType type, float width, float height, Object data, boolean needsExtraHeight) {
            this.type = type;
            this.width = width;
            this.height = height;
            this.data = data;
            this.needsExtraHeight = needsExtraHeight;
        }
    }

    private static class RenderContext {
        final String timeString;
        final float timeWidth;
        final Color timeColor;

        RenderContext(int screenWidth) {
            Font font = FontsContext.REGULAR.getFont(9f);
            timeString = LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm"));
            timeWidth = font.getFont().getWidth(timeString, 9f);
            timeColor = Color.WHITE;
        }
    }

    private static class BossBarInfo {
        final String timeString, labelText;
        final float timeWidth, labelWidth;

        BossBarInfo(String timeString, String labelText, float timeWidth, float labelWidth) {
            this.timeString = timeString;
            this.labelText = labelText;
            this.timeWidth = timeWidth;
            this.labelWidth = labelWidth;
        }
    }

    private static class SimpleAnimation {
        private float current, target;
        private final long duration;
        private long start;
        private boolean running;

        SimpleAnimation(float val, long duration) {
            this.current = this.target = val;
            this.duration = duration;
        }

        void animateTo(float newTarget) {
            target = newTarget;
            start = System.currentTimeMillis();
            running = true;
        }

        float getOutput() {
            if (!running) return current;

            long elapsed = System.currentTimeMillis() - start;
            float progress = Math.min(1f, (float) elapsed / duration);
            current = current + progress * (target - current);

            if (progress >= 1f) {
                running = false;
                current = target;
            }
            return current;
        }
    }
}
MediaUtils:
Expand Collapse Copy
package ru.flow.api.media;

import by.bonenaut7.mediatransport4j.api.MediaSession;
import by.bonenaut7.mediatransport4j.api.MediaTransport;
import com.google.common.io.BaseEncoding;
import net.minecraft.client.texture.AbstractTexture;
import ru.flow.base.utils.render.Render2DUtil;
import ru.flow.base.utils.render.RenderContext;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.nio.ByteBuffer;
import java.security.MessageDigest;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class MediaUtils {

    private static boolean initialized = false;
    private static final ScheduledExecutorService s = Executors.newSingleThreadScheduledExecutor();
    private static volatile MediaInfo mediaInfo = null;
    public static volatile Color lastAlbumColor = Color.WHITE;

    private static final Map<String, AbstractTexture> textureCache = new ConcurrentHashMap<>();
    private static String previousHash = "";

    public static class MediaInfo {
        public final String title;
        public final String artist;
        public final String textureHash;

        public MediaInfo(String title, String artist, String textureHash) {
            this.title = title;
            this.artist = artist;
            this.textureHash = textureHash;
        }

        public AbstractTexture getTexture() {
            return textureCache.get(textureHash);
        }
    }

    public static MediaInfo getCurrentMedia() {
        if (!initialized) {
            boolean bb = MediaTransport.init();
            initialized = true;
            s.scheduleAtFixedRate(() -> {
                try {
                    List<MediaSession> sessions = MediaTransport.getMediaSessions();
                    if (sessions != null && !sessions.isEmpty()) {
                        final MediaSession mediaSession = sessions.get(0);

                        String hash = "";
                        AbstractTexture texture = null;

                        if (mediaSession.hasThumbnail()) {
                            ByteBuffer buf = mediaSession.getThumbnail();
                            hash = hashBuffer(buf);

                            if (!hash.equals(previousHash)) {
                                AbstractTexture old = textureCache.remove(previousHash);
                                if (old != null) old.close();

                                texture = convertTexture(buf);
                                if (texture != null) {
                                    textureCache.put(hash, texture);
                                }
                                previousHash = hash;
                            }
                        }

                        mediaInfo = new MediaInfo(mediaSession.getTitle(), mediaSession.getArtist(), hash);
                    } else {
                        clearCache();
                        mediaInfo = null;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }, 0, 50, TimeUnit.MILLISECONDS);
        }
        return mediaInfo;
    }

    public static Color getAverageColor(BufferedImage img) {
        long r = 0, g = 0, b = 0;
        int count = 0;

        int step = 5;
        for (int x = 0; x < img.getWidth(); x += step) {
            for (int y = 0; y < img.getHeight(); y += step) {
                int rgb = img.getRGB(x, y);
                r += (rgb >> 16) & 0xFF;
                g += (rgb >> 8) & 0xFF;
                b += (rgb) & 0xFF;
                count++;
            }
        }

        if (count == 0) return new Color(255, 255, 255);
        return new Color((int)(r / count), (int)(g / count), (int)(b / count));
    }

    private static AbstractTexture convertTexture(ByteBuffer buffer) {
        try {
            BufferedImage img = ImageIO.read(new ByteArrayInputStream(buffer.array()));
            if (img != null) {
                lastAlbumColor = getAverageColor(img);
                return RenderContext.convert(img);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }



    private static String hashBuffer(ByteBuffer buffer) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(buffer.array());
            return BaseEncoding.base16().lowerCase().encode(md.digest());
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    private static void clearCache() {
        textureCache.values().forEach(AbstractTexture::close);
        textureCache.clear();
        previousHash = "";
    }
}
прикольно
 
прикольно, ток
1775380347882.png
что это за 2 полосочки
 
Пожалуйста, авторизуйтесь для просмотра ссылки.

DynamicIsland:
Expand Collapse Copy
package ru.flow.client.screens.widgets;

import lombok.Getter;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.hud.BossBarHud;
import net.minecraft.client.gui.hud.ClientBossBar;
import net.minecraft.client.gui.hud.InGameHud;
import net.minecraft.client.network.PlayerListEntry;
import net.minecraft.client.texture.AbstractTexture;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.Nullable;
import ru.flow.api.client.widget.AbstractWidget;
import ru.flow.api.media.MediaUtils;
import ru.flow.api.system.animation.Direction;
import ru.flow.api.system.animation.Easing;
import ru.flow.api.system.animation.implement.WaveAnimation;
import ru.flow.base.GlobalRefs;
import ru.flow.base.utils.font.Font;
import ru.flow.base.utils.font.FontsContext;
import ru.flow.base.utils.shape.states.ColorState;
import ru.flow.base.utils.shape.states.RadiusState;
import ru.flow.client.modules.render.Interface;

import java.awt.*;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Getter
public class DynamicIsland extends AbstractWidget implements GlobalRefs {

    private static final long DISPLAY_MS = 2000L;
    private static final Color COLOR_GREEN = new Color(0xFF46FF00, true);
    private static final Color COLOR_RED = new Color(0xFFFF4242, true);
    private static final Color COLOR_DEFAULT = new Color(0xFFA442FF, true);

    private static volatile String currentLabel = "Mytheria";
    private static volatile Color currentStatusColor = COLOR_DEFAULT;
    private static volatile NotificationType currentNotificationType = NotificationType.DEFAULT;
    private static volatile long resetAt = 0L;

    private final WaveAnimation[] waveAnimations = new WaveAnimation[4];
    private final SimpleAnimation widthAnimation, heightAnimation;

    public DynamicIsland() {
        super("DynamicIsland", 10, 10, 128, 15, true);
        widthAnimation = new SimpleAnimation(0f, 30);
        heightAnimation = new SimpleAnimation(0f, 30);

        for (int i = 0; i < 4; i++) {
            waveAnimations[i] = new WaveAnimation(450 + (int)(Math.random() * 250), 10, Easing.BOTH_SINE);
        }
    }

    public static void addNotification(String text, NotificationType type) {
        currentLabel = text;
        currentNotificationType = type;
        currentStatusColor = type.color;
        resetAt = System.currentTimeMillis() + DISPLAY_MS;
    }

    public static void notifyModuleToggle(String moduleName, boolean enabled) {
        addNotification(moduleName + (enabled ? " включен" : " выключен"),
                enabled ? NotificationType.SUCCESS : NotificationType.ERROR);
    }

    public static void strengthNotification() {
        if (mc.player == null) return;
        float criticalThreshold = 0.1f;

        ItemStack[] armorSlots = {
                mc.player.getEquippedStack(EquipmentSlot.FEET),
                mc.player.getEquippedStack(EquipmentSlot.LEGS),
                mc.player.getEquippedStack(EquipmentSlot.CHEST),
                mc.player.getEquippedStack(EquipmentSlot.HEAD)
        };

        String[] slotNames = {"Ботинки", "Поножи", "Нагрудник", "Шлем"};

        for (int i = 0; i < armorSlots.length; i++) {
            ItemStack armor = armorSlots[i];
            if (armor.isEmpty() || !armor.isDamageable()) continue;

            int maxDurability = armor.getMaxDamage();
            int currentDamage = armor.getDamage();
            int durabilityLeft = maxDurability - currentDamage;
            float durabilityPercent = (float) durabilityLeft / maxDurability;

            if (durabilityPercent <= criticalThreshold && durabilityPercent > 0) {
                addNotification(slotNames[i] + " имеет низкую прочность!", NotificationType.WARNING);
                return;
            }
        }
    }

    @Override
    public void drawWidget(DrawContext context) {
        renderWatermark(context.getMatrices(), context.getScaledWindowWidth());
    }

    private void renderWatermark(MatrixStack ms, int screenWidth) {
        if (resetAt != 0L && System.currentTimeMillis() >= resetAt) {
            currentLabel = "Mytheria";
            currentStatusColor = COLOR_DEFAULT;
            currentNotificationType = NotificationType.DEFAULT;
            resetAt = 0L;
        }

        RenderContext ctx = new RenderContext(screenWidth);
        WatermarkContent content = determineContent();

        animateDimensions(content);

        float w = widthAnimation.getOutput();
        float h = heightAnimation.getOutput();
        float x = screenWidth / 2f - (w + ctx.timeWidth + 6f) / 2f + ctx.timeWidth - 6f;
        float y = 7f;

        renderTime(ms, ctx, x, y, h);
        renderBackground(ms, x, y, w, h);
        renderContent(ms, content, x, y, w, h);
        renderConnectionIndicator(ms, ctx, x, y, w, h);
    }

    private WatermarkContent determineContent() {
        if (System.currentTimeMillis() < resetAt) {
            return createNotificationContent();
        }

        ClientBossBar bossBar = getPrimaryBossBar();
        if (bossBar != null) return createBossBarContent(bossBar);

        MediaUtils.MediaInfo media = MediaUtils.getCurrentMedia();
        if (media != null && media.getTexture() != null) return createMediaContent(media);

        return createDefaultContent();
    }

    private WatermarkContent createNotificationContent() {
        Font font = FontsContext.REGULAR.getFont(9f);
        float labelW = font.getFont().getWidth(currentLabel, 9f);
        return new WatermarkContent(ContentType.NOTIFICATION, 11f + 3f + labelW + 7.5f,
                Math.max(11f, 11f), currentLabel, false);
    }

    private WatermarkContent createBossBarContent(ClientBossBar bar) {
        float[] size = calculateBossBarSize(bar);
        return new WatermarkContent(ContentType.BOSS_BAR, size[0], size[1], bar, true);
    }

    private WatermarkContent createMediaContent(MediaUtils.MediaInfo media) {
        Font font = FontsContext.REGULAR.getFont(9f);
        float trackW = font.getFont().getWidth(media.title, 9f);
        float waveW = 4 * 2.5f + 3 * 1f + 2f;
        return new WatermarkContent(ContentType.MEDIA, 11f + 4f + trackW + 3f + waveW,
                Math.max(11f, 11f), media, false);
    }

    private WatermarkContent createDefaultContent() {
        Font font = FontsContext.REGULAR.getFont(9f);
        float labelW = font.getFont().getWidth(currentLabel, 9f);
        return new WatermarkContent(ContentType.DEFAULT, 11f + 4f + labelW + 2,
                Math.max(11f, 11f), currentLabel, false);
    }

    private void renderContent(MatrixStack ms, WatermarkContent content, float x, float y, float w, float h) {
        float cx = x + 6f;
        float cy = y + (h - content.height) / 2f;

        switch (content.type) {
            case NOTIFICATION:
                renderStatusBox(ms, cx, cy, content.height, currentStatusColor);
                renderLabel(ms, currentLabel, cx + 13f, cy, content.height);
                break;
            case BOSS_BAR:
                renderBossBar(ms, (ClientBossBar) content.data, cx + 2f, cy + 15f, content.width, 2f);
                break;
            case MEDIA:
                renderMediaInfo(ms, (MediaUtils.MediaInfo) content.data, cx, cy, content.height);
                break;
            case DEFAULT:
                renderStatusBox(ms, cx, cy, content.height, currentStatusColor);
                renderLabel(ms, currentLabel, cx + 14f, cy, content.height);
                break;
        }
    }

    private void renderMediaInfo(MatrixStack ms, MediaUtils.MediaInfo media, float x, float y, float h) {
        float size = 14f;
        ru.flow.base.utils.render.RenderContext.drawTexture(ms, x - 3.5f, y + (h - size) / 2f - 1f,
                size, size, 5.5f, media.getTexture(), Color.WHITE);

        renderLabel(ms, media.title, x + 14f, y, h);
        renderWaveAnimation(ms, x, y, h, media);
    }

    private void renderWaveAnimation(MatrixStack ms, float baseX, float baseY, float h, MediaUtils.MediaInfo media) {
        Font font = FontsContext.REGULAR.getFont(9f);
        float trackW = font.getFont().getWidth(media.title, 9f);
        float textEndX = baseX + 11f + 4f + trackW + 4f;
        float groupW = 4 * (2.5f + 1f) - 1f;
        float centerX = textEndX + groupW / 2f;
        float waveY = baseY + h + 5f;

        for (WaveAnimation anim : waveAnimations) {
            if (anim.isFinished(anim.getDirection())) {
                if (anim.getDirection() == Direction.FORWARDS) {
                    anim.setDirection(Direction.BACKWARDS);
                } else {
                    anim.setValue(4 + Math.random() * 2);
                    anim.setMs(350 + (int)(Math.random() * 400));
                    anim.setDirection(Direction.FORWARDS);
                }
            }
        }

        Color waveColor = desaturate(MediaUtils.lastAlbumColor, 0.5f);
        for (int i = 0; i < 4; i++) {
            double half = waveAnimations[i].getOutput();
            float barX = centerX + (i - 2f) * 3.5f;
            ru.flow.base.utils.render.RenderContext.drawRound(barX + 3, waveY - (float)half - 11,
                    2.3f, (float)(half * 2), 0.7f, waveColor, ms);
        }
    }

    private void renderTime(MatrixStack ms, RenderContext ctx, float x, float y, float h) {
        float timeX = x - ctx.timeWidth - 6f;
        float timeY = y + (h - 9f) / 2f + 1f;
        ru.flow.base.utils.render.RenderContext.drawText(FontsContext.MEDIUM.getFont(9f),
                ctx.timeString, timeX - 3, timeY, ctx.timeColor.getRGB(), ms.peek().getPositionMatrix());
    }

    private void renderBackground(MatrixStack ms, float x, float y, float w, float h) {
        MediaUtils.MediaInfo media = MediaUtils.getCurrentMedia();
        Color bg = media != null && media.getTexture() != null
                ? desaturate(MediaUtils.lastAlbumColor, 0.5f)
                : new Color(0xFF464646, true);
        float blur = media != null && media.getTexture() != null ? 55f : 25f;

        ru.flow.base.utils.render.RenderContext.drawBlur(ms, x, y, w - 8, h - 2,
                new ColorState(bg), new RadiusState(8.5), 1f, blur);
    }

    private void renderStatusBox(MatrixStack ms, float x, float y, float h, Color color) {

        ru.flow.base.utils.render.RenderContext.drawRound(x - 1.5f, y + (h - 11f) / 2f - 1,
                11f, 11f, 4.5f, color, ms);
    }

    private void renderLabel(MatrixStack ms, String text, float x, float y, float h) {
        ru.flow.base.utils.render.RenderContext.drawText(FontsContext.MEDIUM.getFont(9f),
                text, x, y - 1f + (h - 9f) / 2f + 1.25f, Color.WHITE.getRGB(), ms.peek().getPositionMatrix());
    }

    private void renderBossBar(MatrixStack ms, ClientBossBar bar, float x, float y, float w, float h) {
        BossBarInfo info = extractBossBarInfo(bar);
        float timeBoxW = info.timeWidth + 10f;
        float totalW = timeBoxW + info.labelWidth;
        float cx = x + (w - totalW) / 2f;
        float ty = y - 9f - 4f;

        ru.flow.base.utils.render.RenderContext.drawRound(cx -5.5f, ty - 2f, timeBoxW, 11.5f, 3, COLOR_RED, ms);
        ru.flow.base.utils.render.RenderContext.drawText(FontsContext.MEDIUM.getFont(9f),
                info.timeString, cx - 1, ty, Color.WHITE.getRGB(), ms.peek().getPositionMatrix());
        ru.flow.base.utils.render.RenderContext.drawText(FontsContext.MEDIUM.getFont(9f),
                info.labelText, cx + timeBoxW - 3, ty, Color.WHITE.getRGB(), ms.peek().getPositionMatrix());
    }

    private void renderConnectionIndicator(MatrixStack ms, RenderContext ctx, float x, float y, float w, float h) {
        float ix = x + w;
        float iy = y + (h - 9f) / 2f - 3f;

        if (Interface.getInstance().conIcon.isSelected("Обычная")) {
            String symbol = mc.isInSingleplayer() ? "A" : "B";
            ru.flow.base.utils.render.RenderContext.drawText(FontsContext.ICF.getFont(12f),
                    symbol, ix, iy + 1.5f, ctx.timeColor.getRGB(), ms.peek().getPositionMatrix());
        } else if (Interface.getInstance().conIcon.isSelected("Продвинутая")) {
            if (mc.isInSingleplayer()) {
                ru.flow.base.utils.render.RenderContext.drawText(FontsContext.ICF.getFont(12f),
                        "A", ix, iy + 1.5f, ctx.timeColor.getRGB(), ms.peek().getPositionMatrix());
            } else {
                renderConnectionQuality(ms, ix, iy + 2f);
            }
        }
    }

    private void renderConnectionQuality(MatrixStack ms, float x, float y) {
        int ping = getPlayerPing();
        int white = ping <= 60 ? 4 : ping <= 80 ? 3 : ping <= 100 ? 2 : ping <= 120 ? 1 : 0;
        int[] heights = {4, 6, 8, 10};

        for (int i = 0; i < 4; i++) {
            Color c = i < white ? new Color(0xDDFFFFFF, true) : new Color(0x3DFFFFFF, true);
            float bh = heights[i];
            ru.flow.base.utils.render.RenderContext.drawRound(x + i * 3.3f, y + (10 - bh),
                    3f, bh, 0.2f, c, ms);
        }
    }

    private void animateDimensions(WatermarkContent content) {
        float w = content.width + 20f;
        float h = Math.max(20f, content.height + 8f);
        if (content.needsExtraHeight) h -= 1f;

        if (Math.abs(widthAnimation.getOutput() - w) > 0.5f) widthAnimation.animateTo(w);
        if (Math.abs(heightAnimation.getOutput() - h) > 0.5f) heightAnimation.animateTo(h);
    }

    private @Nullable ClientBossBar getPrimaryBossBar() {
        InGameHud hud = mc.inGameHud;
        BossBarHud bossBarHud = hud.getBossBarHud();
        Map<UUID, ClientBossBar> bars = bossBarHud.bossBars;
        return bars.isEmpty() ? null : bars.values().iterator().next();
    }


    private int getPlayerPing() {
        if (mc.player == null || mc.getNetworkHandler() == null) return 0;
        PlayerListEntry entry = mc.getNetworkHandler().getPlayerListEntry(mc.player.getUuid());
        return entry != null ? entry.getLatency() : 0;
    }

    private BossBarInfo extractBossBarInfo(ClientBossBar bar) {
        String raw = bar.getName().getString();
        Font font = FontsContext.REGULAR.getFont(9f);

        Pattern pattern = Pattern.compile("(\\d+)(?!.*\\d)");
        Matcher matcher = pattern.matcher(raw);
        String time = matcher.find() ? matcher.group(1) + "s" : "??s";

        String label = raw.replaceAll(",?\\s*до конца.*$", "")
                .replaceAll("Телепортация.*", "Телепортация").trim();

        return new BossBarInfo(time, label,
                font.getFont().getWidth(time, 9f),
                font.getFont().getWidth(label, 9f));
    }

    private float[] calculateBossBarSize(ClientBossBar bar) {
        BossBarInfo info = extractBossBarInfo(bar);
        return new float[] { info.timeWidth + 16f + info.labelWidth, 13f };
    }

    private Color desaturate(Color c, float factor) {
        float[] hsb = Color.RGBtoHSB(c.getRed(), c.getGreen(), c.getBlue(), null);
        hsb[1] *= factor;
        return new Color(Color.HSBtoRGB(hsb[0], hsb[1], hsb[2]));
    }

    public enum NotificationType {
        SUCCESS(new Color(0xFF46FF00, true)),
        ERROR(new Color(0xFFFF4242, true)),
        WARNING(new Color(0xFFFFAA00, true)),
        INFO(new Color(0xFF42A5FF, true)),
        DEFAULT(new Color(0xFFA442FF, true));

        public final Color color;
        NotificationType(Color color) { this.color = color; }
    }

    private enum ContentType { NOTIFICATION, BOSS_BAR, MEDIA, DEFAULT }

    private static class WatermarkContent {
        final ContentType type;
        final float width, height;
        final Object data;
        final boolean needsExtraHeight;

        WatermarkContent(ContentType type, float width, float height, Object data, boolean needsExtraHeight) {
            this.type = type;
            this.width = width;
            this.height = height;
            this.data = data;
            this.needsExtraHeight = needsExtraHeight;
        }
    }

    private static class RenderContext {
        final String timeString;
        final float timeWidth;
        final Color timeColor;

        RenderContext(int screenWidth) {
            Font font = FontsContext.REGULAR.getFont(9f);
            timeString = LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm"));
            timeWidth = font.getFont().getWidth(timeString, 9f);
            timeColor = Color.WHITE;
        }
    }

    private static class BossBarInfo {
        final String timeString, labelText;
        final float timeWidth, labelWidth;

        BossBarInfo(String timeString, String labelText, float timeWidth, float labelWidth) {
            this.timeString = timeString;
            this.labelText = labelText;
            this.timeWidth = timeWidth;
            this.labelWidth = labelWidth;
        }
    }

    private static class SimpleAnimation {
        private float current, target;
        private final long duration;
        private long start;
        private boolean running;

        SimpleAnimation(float val, long duration) {
            this.current = this.target = val;
            this.duration = duration;
        }

        void animateTo(float newTarget) {
            target = newTarget;
            start = System.currentTimeMillis();
            running = true;
        }

        float getOutput() {
            if (!running) return current;

            long elapsed = System.currentTimeMillis() - start;
            float progress = Math.min(1f, (float) elapsed / duration);
            current = current + progress * (target - current);

            if (progress >= 1f) {
                running = false;
                current = target;
            }
            return current;
        }
    }
}
MediaUtils:
Expand Collapse Copy
package ru.flow.api.media;

import by.bonenaut7.mediatransport4j.api.MediaSession;
import by.bonenaut7.mediatransport4j.api.MediaTransport;
import com.google.common.io.BaseEncoding;
import net.minecraft.client.texture.AbstractTexture;
import ru.flow.base.utils.render.Render2DUtil;
import ru.flow.base.utils.render.RenderContext;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.nio.ByteBuffer;
import java.security.MessageDigest;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class MediaUtils {

    private static boolean initialized = false;
    private static final ScheduledExecutorService s = Executors.newSingleThreadScheduledExecutor();
    private static volatile MediaInfo mediaInfo = null;
    public static volatile Color lastAlbumColor = Color.WHITE;

    private static final Map<String, AbstractTexture> textureCache = new ConcurrentHashMap<>();
    private static String previousHash = "";

    public static class MediaInfo {
        public final String title;
        public final String artist;
        public final String textureHash;

        public MediaInfo(String title, String artist, String textureHash) {
            this.title = title;
            this.artist = artist;
            this.textureHash = textureHash;
        }

        public AbstractTexture getTexture() {
            return textureCache.get(textureHash);
        }
    }

    public static MediaInfo getCurrentMedia() {
        if (!initialized) {
            boolean bb = MediaTransport.init();
            initialized = true;
            s.scheduleAtFixedRate(() -> {
                try {
                    List<MediaSession> sessions = MediaTransport.getMediaSessions();
                    if (sessions != null && !sessions.isEmpty()) {
                        final MediaSession mediaSession = sessions.get(0);

                        String hash = "";
                        AbstractTexture texture = null;

                        if (mediaSession.hasThumbnail()) {
                            ByteBuffer buf = mediaSession.getThumbnail();
                            hash = hashBuffer(buf);

                            if (!hash.equals(previousHash)) {
                                AbstractTexture old = textureCache.remove(previousHash);
                                if (old != null) old.close();

                                texture = convertTexture(buf);
                                if (texture != null) {
                                    textureCache.put(hash, texture);
                                }
                                previousHash = hash;
                            }
                        }

                        mediaInfo = new MediaInfo(mediaSession.getTitle(), mediaSession.getArtist(), hash);
                    } else {
                        clearCache();
                        mediaInfo = null;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }, 0, 50, TimeUnit.MILLISECONDS);
        }
        return mediaInfo;
    }

    public static Color getAverageColor(BufferedImage img) {
        long r = 0, g = 0, b = 0;
        int count = 0;

        int step = 5;
        for (int x = 0; x < img.getWidth(); x += step) {
            for (int y = 0; y < img.getHeight(); y += step) {
                int rgb = img.getRGB(x, y);
                r += (rgb >> 16) & 0xFF;
                g += (rgb >> 8) & 0xFF;
                b += (rgb) & 0xFF;
                count++;
            }
        }

        if (count == 0) return new Color(255, 255, 255);
        return new Color((int)(r / count), (int)(g / count), (int)(b / count));
    }

    private static AbstractTexture convertTexture(ByteBuffer buffer) {
        try {
            BufferedImage img = ImageIO.read(new ByteArrayInputStream(buffer.array()));
            if (img != null) {
                lastAlbumColor = getAverageColor(img);
                return RenderContext.convert(img);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }



    private static String hashBuffer(ByteBuffer buffer) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(buffer.array());
            return BaseEncoding.base16().lowerCase().encode(md.digest());
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    private static void clearCache() {
        textureCache.values().forEach(AbstractTexture::close);
        textureCache.clear();
        previousHash = "";
    }
}
в общем не плохо, но что за 2 полоски
 
Пожалуйста, авторизуйтесь для просмотра ссылки.

DynamicIsland:
Expand Collapse Copy
package ru.flow.client.screens.widgets;

import lombok.Getter;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.hud.BossBarHud;
import net.minecraft.client.gui.hud.ClientBossBar;
import net.minecraft.client.gui.hud.InGameHud;
import net.minecraft.client.network.PlayerListEntry;
import net.minecraft.client.texture.AbstractTexture;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.Nullable;
import ru.flow.api.client.widget.AbstractWidget;
import ru.flow.api.media.MediaUtils;
import ru.flow.api.system.animation.Direction;
import ru.flow.api.system.animation.Easing;
import ru.flow.api.system.animation.implement.WaveAnimation;
import ru.flow.base.GlobalRefs;
import ru.flow.base.utils.font.Font;
import ru.flow.base.utils.font.FontsContext;
import ru.flow.base.utils.shape.states.ColorState;
import ru.flow.base.utils.shape.states.RadiusState;
import ru.flow.client.modules.render.Interface;

import java.awt.*;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Getter
public class DynamicIsland extends AbstractWidget implements GlobalRefs {

    private static final long DISPLAY_MS = 2000L;
    private static final Color COLOR_GREEN = new Color(0xFF46FF00, true);
    private static final Color COLOR_RED = new Color(0xFFFF4242, true);
    private static final Color COLOR_DEFAULT = new Color(0xFFA442FF, true);

    private static volatile String currentLabel = "Mytheria";
    private static volatile Color currentStatusColor = COLOR_DEFAULT;
    private static volatile NotificationType currentNotificationType = NotificationType.DEFAULT;
    private static volatile long resetAt = 0L;

    private final WaveAnimation[] waveAnimations = new WaveAnimation[4];
    private final SimpleAnimation widthAnimation, heightAnimation;

    public DynamicIsland() {
        super("DynamicIsland", 10, 10, 128, 15, true);
        widthAnimation = new SimpleAnimation(0f, 30);
        heightAnimation = new SimpleAnimation(0f, 30);

        for (int i = 0; i < 4; i++) {
            waveAnimations[i] = new WaveAnimation(450 + (int)(Math.random() * 250), 10, Easing.BOTH_SINE);
        }
    }

    public static void addNotification(String text, NotificationType type) {
        currentLabel = text;
        currentNotificationType = type;
        currentStatusColor = type.color;
        resetAt = System.currentTimeMillis() + DISPLAY_MS;
    }

    public static void notifyModuleToggle(String moduleName, boolean enabled) {
        addNotification(moduleName + (enabled ? " включен" : " выключен"),
                enabled ? NotificationType.SUCCESS : NotificationType.ERROR);
    }

    public static void strengthNotification() {
        if (mc.player == null) return;
        float criticalThreshold = 0.1f;

        ItemStack[] armorSlots = {
                mc.player.getEquippedStack(EquipmentSlot.FEET),
                mc.player.getEquippedStack(EquipmentSlot.LEGS),
                mc.player.getEquippedStack(EquipmentSlot.CHEST),
                mc.player.getEquippedStack(EquipmentSlot.HEAD)
        };

        String[] slotNames = {"Ботинки", "Поножи", "Нагрудник", "Шлем"};

        for (int i = 0; i < armorSlots.length; i++) {
            ItemStack armor = armorSlots[i];
            if (armor.isEmpty() || !armor.isDamageable()) continue;

            int maxDurability = armor.getMaxDamage();
            int currentDamage = armor.getDamage();
            int durabilityLeft = maxDurability - currentDamage;
            float durabilityPercent = (float) durabilityLeft / maxDurability;

            if (durabilityPercent <= criticalThreshold && durabilityPercent > 0) {
                addNotification(slotNames[i] + " имеет низкую прочность!", NotificationType.WARNING);
                return;
            }
        }
    }

    @Override
    public void drawWidget(DrawContext context) {
        renderWatermark(context.getMatrices(), context.getScaledWindowWidth());
    }

    private void renderWatermark(MatrixStack ms, int screenWidth) {
        if (resetAt != 0L && System.currentTimeMillis() >= resetAt) {
            currentLabel = "Mytheria";
            currentStatusColor = COLOR_DEFAULT;
            currentNotificationType = NotificationType.DEFAULT;
            resetAt = 0L;
        }

        RenderContext ctx = new RenderContext(screenWidth);
        WatermarkContent content = determineContent();

        animateDimensions(content);

        float w = widthAnimation.getOutput();
        float h = heightAnimation.getOutput();
        float x = screenWidth / 2f - (w + ctx.timeWidth + 6f) / 2f + ctx.timeWidth - 6f;
        float y = 7f;

        renderTime(ms, ctx, x, y, h);
        renderBackground(ms, x, y, w, h);
        renderContent(ms, content, x, y, w, h);
        renderConnectionIndicator(ms, ctx, x, y, w, h);
    }

    private WatermarkContent determineContent() {
        if (System.currentTimeMillis() < resetAt) {
            return createNotificationContent();
        }

        ClientBossBar bossBar = getPrimaryBossBar();
        if (bossBar != null) return createBossBarContent(bossBar);

        MediaUtils.MediaInfo media = MediaUtils.getCurrentMedia();
        if (media != null && media.getTexture() != null) return createMediaContent(media);

        return createDefaultContent();
    }

    private WatermarkContent createNotificationContent() {
        Font font = FontsContext.REGULAR.getFont(9f);
        float labelW = font.getFont().getWidth(currentLabel, 9f);
        return new WatermarkContent(ContentType.NOTIFICATION, 11f + 3f + labelW + 7.5f,
                Math.max(11f, 11f), currentLabel, false);
    }

    private WatermarkContent createBossBarContent(ClientBossBar bar) {
        float[] size = calculateBossBarSize(bar);
        return new WatermarkContent(ContentType.BOSS_BAR, size[0], size[1], bar, true);
    }

    private WatermarkContent createMediaContent(MediaUtils.MediaInfo media) {
        Font font = FontsContext.REGULAR.getFont(9f);
        float trackW = font.getFont().getWidth(media.title, 9f);
        float waveW = 4 * 2.5f + 3 * 1f + 2f;
        return new WatermarkContent(ContentType.MEDIA, 11f + 4f + trackW + 3f + waveW,
                Math.max(11f, 11f), media, false);
    }

    private WatermarkContent createDefaultContent() {
        Font font = FontsContext.REGULAR.getFont(9f);
        float labelW = font.getFont().getWidth(currentLabel, 9f);
        return new WatermarkContent(ContentType.DEFAULT, 11f + 4f + labelW + 2,
                Math.max(11f, 11f), currentLabel, false);
    }

    private void renderContent(MatrixStack ms, WatermarkContent content, float x, float y, float w, float h) {
        float cx = x + 6f;
        float cy = y + (h - content.height) / 2f;

        switch (content.type) {
            case NOTIFICATION:
                renderStatusBox(ms, cx, cy, content.height, currentStatusColor);
                renderLabel(ms, currentLabel, cx + 13f, cy, content.height);
                break;
            case BOSS_BAR:
                renderBossBar(ms, (ClientBossBar) content.data, cx + 2f, cy + 15f, content.width, 2f);
                break;
            case MEDIA:
                renderMediaInfo(ms, (MediaUtils.MediaInfo) content.data, cx, cy, content.height);
                break;
            case DEFAULT:
                renderStatusBox(ms, cx, cy, content.height, currentStatusColor);
                renderLabel(ms, currentLabel, cx + 14f, cy, content.height);
                break;
        }
    }

    private void renderMediaInfo(MatrixStack ms, MediaUtils.MediaInfo media, float x, float y, float h) {
        float size = 14f;
        ru.flow.base.utils.render.RenderContext.drawTexture(ms, x - 3.5f, y + (h - size) / 2f - 1f,
                size, size, 5.5f, media.getTexture(), Color.WHITE);

        renderLabel(ms, media.title, x + 14f, y, h);
        renderWaveAnimation(ms, x, y, h, media);
    }

    private void renderWaveAnimation(MatrixStack ms, float baseX, float baseY, float h, MediaUtils.MediaInfo media) {
        Font font = FontsContext.REGULAR.getFont(9f);
        float trackW = font.getFont().getWidth(media.title, 9f);
        float textEndX = baseX + 11f + 4f + trackW + 4f;
        float groupW = 4 * (2.5f + 1f) - 1f;
        float centerX = textEndX + groupW / 2f;
        float waveY = baseY + h + 5f;

        for (WaveAnimation anim : waveAnimations) {
            if (anim.isFinished(anim.getDirection())) {
                if (anim.getDirection() == Direction.FORWARDS) {
                    anim.setDirection(Direction.BACKWARDS);
                } else {
                    anim.setValue(4 + Math.random() * 2);
                    anim.setMs(350 + (int)(Math.random() * 400));
                    anim.setDirection(Direction.FORWARDS);
                }
            }
        }

        Color waveColor = desaturate(MediaUtils.lastAlbumColor, 0.5f);
        for (int i = 0; i < 4; i++) {
            double half = waveAnimations[i].getOutput();
            float barX = centerX + (i - 2f) * 3.5f;
            ru.flow.base.utils.render.RenderContext.drawRound(barX + 3, waveY - (float)half - 11,
                    2.3f, (float)(half * 2), 0.7f, waveColor, ms);
        }
    }

    private void renderTime(MatrixStack ms, RenderContext ctx, float x, float y, float h) {
        float timeX = x - ctx.timeWidth - 6f;
        float timeY = y + (h - 9f) / 2f + 1f;
        ru.flow.base.utils.render.RenderContext.drawText(FontsContext.MEDIUM.getFont(9f),
                ctx.timeString, timeX - 3, timeY, ctx.timeColor.getRGB(), ms.peek().getPositionMatrix());
    }

    private void renderBackground(MatrixStack ms, float x, float y, float w, float h) {
        MediaUtils.MediaInfo media = MediaUtils.getCurrentMedia();
        Color bg = media != null && media.getTexture() != null
                ? desaturate(MediaUtils.lastAlbumColor, 0.5f)
                : new Color(0xFF464646, true);
        float blur = media != null && media.getTexture() != null ? 55f : 25f;

        ru.flow.base.utils.render.RenderContext.drawBlur(ms, x, y, w - 8, h - 2,
                new ColorState(bg), new RadiusState(8.5), 1f, blur);
    }

    private void renderStatusBox(MatrixStack ms, float x, float y, float h, Color color) {

        ru.flow.base.utils.render.RenderContext.drawRound(x - 1.5f, y + (h - 11f) / 2f - 1,
                11f, 11f, 4.5f, color, ms);
    }

    private void renderLabel(MatrixStack ms, String text, float x, float y, float h) {
        ru.flow.base.utils.render.RenderContext.drawText(FontsContext.MEDIUM.getFont(9f),
                text, x, y - 1f + (h - 9f) / 2f + 1.25f, Color.WHITE.getRGB(), ms.peek().getPositionMatrix());
    }

    private void renderBossBar(MatrixStack ms, ClientBossBar bar, float x, float y, float w, float h) {
        BossBarInfo info = extractBossBarInfo(bar);
        float timeBoxW = info.timeWidth + 10f;
        float totalW = timeBoxW + info.labelWidth;
        float cx = x + (w - totalW) / 2f;
        float ty = y - 9f - 4f;

        ru.flow.base.utils.render.RenderContext.drawRound(cx -5.5f, ty - 2f, timeBoxW, 11.5f, 3, COLOR_RED, ms);
        ru.flow.base.utils.render.RenderContext.drawText(FontsContext.MEDIUM.getFont(9f),
                info.timeString, cx - 1, ty, Color.WHITE.getRGB(), ms.peek().getPositionMatrix());
        ru.flow.base.utils.render.RenderContext.drawText(FontsContext.MEDIUM.getFont(9f),
                info.labelText, cx + timeBoxW - 3, ty, Color.WHITE.getRGB(), ms.peek().getPositionMatrix());
    }

    private void renderConnectionIndicator(MatrixStack ms, RenderContext ctx, float x, float y, float w, float h) {
        float ix = x + w;
        float iy = y + (h - 9f) / 2f - 3f;

        if (Interface.getInstance().conIcon.isSelected("Обычная")) {
            String symbol = mc.isInSingleplayer() ? "A" : "B";
            ru.flow.base.utils.render.RenderContext.drawText(FontsContext.ICF.getFont(12f),
                    symbol, ix, iy + 1.5f, ctx.timeColor.getRGB(), ms.peek().getPositionMatrix());
        } else if (Interface.getInstance().conIcon.isSelected("Продвинутая")) {
            if (mc.isInSingleplayer()) {
                ru.flow.base.utils.render.RenderContext.drawText(FontsContext.ICF.getFont(12f),
                        "A", ix, iy + 1.5f, ctx.timeColor.getRGB(), ms.peek().getPositionMatrix());
            } else {
                renderConnectionQuality(ms, ix, iy + 2f);
            }
        }
    }

    private void renderConnectionQuality(MatrixStack ms, float x, float y) {
        int ping = getPlayerPing();
        int white = ping <= 60 ? 4 : ping <= 80 ? 3 : ping <= 100 ? 2 : ping <= 120 ? 1 : 0;
        int[] heights = {4, 6, 8, 10};

        for (int i = 0; i < 4; i++) {
            Color c = i < white ? new Color(0xDDFFFFFF, true) : new Color(0x3DFFFFFF, true);
            float bh = heights[i];
            ru.flow.base.utils.render.RenderContext.drawRound(x + i * 3.3f, y + (10 - bh),
                    3f, bh, 0.2f, c, ms);
        }
    }

    private void animateDimensions(WatermarkContent content) {
        float w = content.width + 20f;
        float h = Math.max(20f, content.height + 8f);
        if (content.needsExtraHeight) h -= 1f;

        if (Math.abs(widthAnimation.getOutput() - w) > 0.5f) widthAnimation.animateTo(w);
        if (Math.abs(heightAnimation.getOutput() - h) > 0.5f) heightAnimation.animateTo(h);
    }

    private @Nullable ClientBossBar getPrimaryBossBar() {
        InGameHud hud = mc.inGameHud;
        BossBarHud bossBarHud = hud.getBossBarHud();
        Map<UUID, ClientBossBar> bars = bossBarHud.bossBars;
        return bars.isEmpty() ? null : bars.values().iterator().next();
    }


    private int getPlayerPing() {
        if (mc.player == null || mc.getNetworkHandler() == null) return 0;
        PlayerListEntry entry = mc.getNetworkHandler().getPlayerListEntry(mc.player.getUuid());
        return entry != null ? entry.getLatency() : 0;
    }

    private BossBarInfo extractBossBarInfo(ClientBossBar bar) {
        String raw = bar.getName().getString();
        Font font = FontsContext.REGULAR.getFont(9f);

        Pattern pattern = Pattern.compile("(\\d+)(?!.*\\d)");
        Matcher matcher = pattern.matcher(raw);
        String time = matcher.find() ? matcher.group(1) + "s" : "??s";

        String label = raw.replaceAll(",?\\s*до конца.*$", "")
                .replaceAll("Телепортация.*", "Телепортация").trim();

        return new BossBarInfo(time, label,
                font.getFont().getWidth(time, 9f),
                font.getFont().getWidth(label, 9f));
    }

    private float[] calculateBossBarSize(ClientBossBar bar) {
        BossBarInfo info = extractBossBarInfo(bar);
        return new float[] { info.timeWidth + 16f + info.labelWidth, 13f };
    }

    private Color desaturate(Color c, float factor) {
        float[] hsb = Color.RGBtoHSB(c.getRed(), c.getGreen(), c.getBlue(), null);
        hsb[1] *= factor;
        return new Color(Color.HSBtoRGB(hsb[0], hsb[1], hsb[2]));
    }

    public enum NotificationType {
        SUCCESS(new Color(0xFF46FF00, true)),
        ERROR(new Color(0xFFFF4242, true)),
        WARNING(new Color(0xFFFFAA00, true)),
        INFO(new Color(0xFF42A5FF, true)),
        DEFAULT(new Color(0xFFA442FF, true));

        public final Color color;
        NotificationType(Color color) { this.color = color; }
    }

    private enum ContentType { NOTIFICATION, BOSS_BAR, MEDIA, DEFAULT }

    private static class WatermarkContent {
        final ContentType type;
        final float width, height;
        final Object data;
        final boolean needsExtraHeight;

        WatermarkContent(ContentType type, float width, float height, Object data, boolean needsExtraHeight) {
            this.type = type;
            this.width = width;
            this.height = height;
            this.data = data;
            this.needsExtraHeight = needsExtraHeight;
        }
    }

    private static class RenderContext {
        final String timeString;
        final float timeWidth;
        final Color timeColor;

        RenderContext(int screenWidth) {
            Font font = FontsContext.REGULAR.getFont(9f);
            timeString = LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm"));
            timeWidth = font.getFont().getWidth(timeString, 9f);
            timeColor = Color.WHITE;
        }
    }

    private static class BossBarInfo {
        final String timeString, labelText;
        final float timeWidth, labelWidth;

        BossBarInfo(String timeString, String labelText, float timeWidth, float labelWidth) {
            this.timeString = timeString;
            this.labelText = labelText;
            this.timeWidth = timeWidth;
            this.labelWidth = labelWidth;
        }
    }

    private static class SimpleAnimation {
        private float current, target;
        private final long duration;
        private long start;
        private boolean running;

        SimpleAnimation(float val, long duration) {
            this.current = this.target = val;
            this.duration = duration;
        }

        void animateTo(float newTarget) {
            target = newTarget;
            start = System.currentTimeMillis();
            running = true;
        }

        float getOutput() {
            if (!running) return current;

            long elapsed = System.currentTimeMillis() - start;
            float progress = Math.min(1f, (float) elapsed / duration);
            current = current + progress * (target - current);

            if (progress >= 1f) {
                running = false;
                current = target;
            }
            return current;
        }
    }
}
MediaUtils:
Expand Collapse Copy
package ru.flow.api.media;

import by.bonenaut7.mediatransport4j.api.MediaSession;
import by.bonenaut7.mediatransport4j.api.MediaTransport;
import com.google.common.io.BaseEncoding;
import net.minecraft.client.texture.AbstractTexture;
import ru.flow.base.utils.render.Render2DUtil;
import ru.flow.base.utils.render.RenderContext;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.nio.ByteBuffer;
import java.security.MessageDigest;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class MediaUtils {

    private static boolean initialized = false;
    private static final ScheduledExecutorService s = Executors.newSingleThreadScheduledExecutor();
    private static volatile MediaInfo mediaInfo = null;
    public static volatile Color lastAlbumColor = Color.WHITE;

    private static final Map<String, AbstractTexture> textureCache = new ConcurrentHashMap<>();
    private static String previousHash = "";

    public static class MediaInfo {
        public final String title;
        public final String artist;
        public final String textureHash;

        public MediaInfo(String title, String artist, String textureHash) {
            this.title = title;
            this.artist = artist;
            this.textureHash = textureHash;
        }

        public AbstractTexture getTexture() {
            return textureCache.get(textureHash);
        }
    }

    public static MediaInfo getCurrentMedia() {
        if (!initialized) {
            boolean bb = MediaTransport.init();
            initialized = true;
            s.scheduleAtFixedRate(() -> {
                try {
                    List<MediaSession> sessions = MediaTransport.getMediaSessions();
                    if (sessions != null && !sessions.isEmpty()) {
                        final MediaSession mediaSession = sessions.get(0);

                        String hash = "";
                        AbstractTexture texture = null;

                        if (mediaSession.hasThumbnail()) {
                            ByteBuffer buf = mediaSession.getThumbnail();
                            hash = hashBuffer(buf);

                            if (!hash.equals(previousHash)) {
                                AbstractTexture old = textureCache.remove(previousHash);
                                if (old != null) old.close();

                                texture = convertTexture(buf);
                                if (texture != null) {
                                    textureCache.put(hash, texture);
                                }
                                previousHash = hash;
                            }
                        }

                        mediaInfo = new MediaInfo(mediaSession.getTitle(), mediaSession.getArtist(), hash);
                    } else {
                        clearCache();
                        mediaInfo = null;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }, 0, 50, TimeUnit.MILLISECONDS);
        }
        return mediaInfo;
    }

    public static Color getAverageColor(BufferedImage img) {
        long r = 0, g = 0, b = 0;
        int count = 0;

        int step = 5;
        for (int x = 0; x < img.getWidth(); x += step) {
            for (int y = 0; y < img.getHeight(); y += step) {
                int rgb = img.getRGB(x, y);
                r += (rgb >> 16) & 0xFF;
                g += (rgb >> 8) & 0xFF;
                b += (rgb) & 0xFF;
                count++;
            }
        }

        if (count == 0) return new Color(255, 255, 255);
        return new Color((int)(r / count), (int)(g / count), (int)(b / count));
    }

    private static AbstractTexture convertTexture(ByteBuffer buffer) {
        try {
            BufferedImage img = ImageIO.read(new ByteArrayInputStream(buffer.array()));
            if (img != null) {
                lastAlbumColor = getAverageColor(img);
                return RenderContext.convert(img);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }



    private static String hashBuffer(ByteBuffer buffer) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(buffer.array());
            return BaseEncoding.base16().lowerCase().encode(md.digest());
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    private static void clearCache() {
        textureCache.values().forEach(AbstractTexture::close);
        textureCache.clear();
        previousHash = "";
    }
}
50/50 + показывание допустим когда Aura включена это тупо ну и есть минусы + код так се
 
Пожалуйста, авторизуйтесь для просмотра ссылки.

DynamicIsland:
Expand Collapse Copy
package ru.flow.client.screens.widgets;

import lombok.Getter;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.hud.BossBarHud;
import net.minecraft.client.gui.hud.ClientBossBar;
import net.minecraft.client.gui.hud.InGameHud;
import net.minecraft.client.network.PlayerListEntry;
import net.minecraft.client.texture.AbstractTexture;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.Nullable;
import ru.flow.api.client.widget.AbstractWidget;
import ru.flow.api.media.MediaUtils;
import ru.flow.api.system.animation.Direction;
import ru.flow.api.system.animation.Easing;
import ru.flow.api.system.animation.implement.WaveAnimation;
import ru.flow.base.GlobalRefs;
import ru.flow.base.utils.font.Font;
import ru.flow.base.utils.font.FontsContext;
import ru.flow.base.utils.shape.states.ColorState;
import ru.flow.base.utils.shape.states.RadiusState;
import ru.flow.client.modules.render.Interface;

import java.awt.*;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Getter
public class DynamicIsland extends AbstractWidget implements GlobalRefs {

    private static final long DISPLAY_MS = 2000L;
    private static final Color COLOR_GREEN = new Color(0xFF46FF00, true);
    private static final Color COLOR_RED = new Color(0xFFFF4242, true);
    private static final Color COLOR_DEFAULT = new Color(0xFFA442FF, true);

    private static volatile String currentLabel = "Mytheria";
    private static volatile Color currentStatusColor = COLOR_DEFAULT;
    private static volatile NotificationType currentNotificationType = NotificationType.DEFAULT;
    private static volatile long resetAt = 0L;

    private final WaveAnimation[] waveAnimations = new WaveAnimation[4];
    private final SimpleAnimation widthAnimation, heightAnimation;

    public DynamicIsland() {
        super("DynamicIsland", 10, 10, 128, 15, true);
        widthAnimation = new SimpleAnimation(0f, 30);
        heightAnimation = new SimpleAnimation(0f, 30);

        for (int i = 0; i < 4; i++) {
            waveAnimations[i] = new WaveAnimation(450 + (int)(Math.random() * 250), 10, Easing.BOTH_SINE);
        }
    }

    public static void addNotification(String text, NotificationType type) {
        currentLabel = text;
        currentNotificationType = type;
        currentStatusColor = type.color;
        resetAt = System.currentTimeMillis() + DISPLAY_MS;
    }

    public static void notifyModuleToggle(String moduleName, boolean enabled) {
        addNotification(moduleName + (enabled ? " включен" : " выключен"),
                enabled ? NotificationType.SUCCESS : NotificationType.ERROR);
    }

    public static void strengthNotification() {
        if (mc.player == null) return;
        float criticalThreshold = 0.1f;

        ItemStack[] armorSlots = {
                mc.player.getEquippedStack(EquipmentSlot.FEET),
                mc.player.getEquippedStack(EquipmentSlot.LEGS),
                mc.player.getEquippedStack(EquipmentSlot.CHEST),
                mc.player.getEquippedStack(EquipmentSlot.HEAD)
        };

        String[] slotNames = {"Ботинки", "Поножи", "Нагрудник", "Шлем"};

        for (int i = 0; i < armorSlots.length; i++) {
            ItemStack armor = armorSlots[i];
            if (armor.isEmpty() || !armor.isDamageable()) continue;

            int maxDurability = armor.getMaxDamage();
            int currentDamage = armor.getDamage();
            int durabilityLeft = maxDurability - currentDamage;
            float durabilityPercent = (float) durabilityLeft / maxDurability;

            if (durabilityPercent <= criticalThreshold && durabilityPercent > 0) {
                addNotification(slotNames[i] + " имеет низкую прочность!", NotificationType.WARNING);
                return;
            }
        }
    }

    @Override
    public void drawWidget(DrawContext context) {
        renderWatermark(context.getMatrices(), context.getScaledWindowWidth());
    }

    private void renderWatermark(MatrixStack ms, int screenWidth) {
        if (resetAt != 0L && System.currentTimeMillis() >= resetAt) {
            currentLabel = "Mytheria";
            currentStatusColor = COLOR_DEFAULT;
            currentNotificationType = NotificationType.DEFAULT;
            resetAt = 0L;
        }

        RenderContext ctx = new RenderContext(screenWidth);
        WatermarkContent content = determineContent();

        animateDimensions(content);

        float w = widthAnimation.getOutput();
        float h = heightAnimation.getOutput();
        float x = screenWidth / 2f - (w + ctx.timeWidth + 6f) / 2f + ctx.timeWidth - 6f;
        float y = 7f;

        renderTime(ms, ctx, x, y, h);
        renderBackground(ms, x, y, w, h);
        renderContent(ms, content, x, y, w, h);
        renderConnectionIndicator(ms, ctx, x, y, w, h);
    }

    private WatermarkContent determineContent() {
        if (System.currentTimeMillis() < resetAt) {
            return createNotificationContent();
        }

        ClientBossBar bossBar = getPrimaryBossBar();
        if (bossBar != null) return createBossBarContent(bossBar);

        MediaUtils.MediaInfo media = MediaUtils.getCurrentMedia();
        if (media != null && media.getTexture() != null) return createMediaContent(media);

        return createDefaultContent();
    }

    private WatermarkContent createNotificationContent() {
        Font font = FontsContext.REGULAR.getFont(9f);
        float labelW = font.getFont().getWidth(currentLabel, 9f);
        return new WatermarkContent(ContentType.NOTIFICATION, 11f + 3f + labelW + 7.5f,
                Math.max(11f, 11f), currentLabel, false);
    }

    private WatermarkContent createBossBarContent(ClientBossBar bar) {
        float[] size = calculateBossBarSize(bar);
        return new WatermarkContent(ContentType.BOSS_BAR, size[0], size[1], bar, true);
    }

    private WatermarkContent createMediaContent(MediaUtils.MediaInfo media) {
        Font font = FontsContext.REGULAR.getFont(9f);
        float trackW = font.getFont().getWidth(media.title, 9f);
        float waveW = 4 * 2.5f + 3 * 1f + 2f;
        return new WatermarkContent(ContentType.MEDIA, 11f + 4f + trackW + 3f + waveW,
                Math.max(11f, 11f), media, false);
    }

    private WatermarkContent createDefaultContent() {
        Font font = FontsContext.REGULAR.getFont(9f);
        float labelW = font.getFont().getWidth(currentLabel, 9f);
        return new WatermarkContent(ContentType.DEFAULT, 11f + 4f + labelW + 2,
                Math.max(11f, 11f), currentLabel, false);
    }

    private void renderContent(MatrixStack ms, WatermarkContent content, float x, float y, float w, float h) {
        float cx = x + 6f;
        float cy = y + (h - content.height) / 2f;

        switch (content.type) {
            case NOTIFICATION:
                renderStatusBox(ms, cx, cy, content.height, currentStatusColor);
                renderLabel(ms, currentLabel, cx + 13f, cy, content.height);
                break;
            case BOSS_BAR:
                renderBossBar(ms, (ClientBossBar) content.data, cx + 2f, cy + 15f, content.width, 2f);
                break;
            case MEDIA:
                renderMediaInfo(ms, (MediaUtils.MediaInfo) content.data, cx, cy, content.height);
                break;
            case DEFAULT:
                renderStatusBox(ms, cx, cy, content.height, currentStatusColor);
                renderLabel(ms, currentLabel, cx + 14f, cy, content.height);
                break;
        }
    }

    private void renderMediaInfo(MatrixStack ms, MediaUtils.MediaInfo media, float x, float y, float h) {
        float size = 14f;
        ru.flow.base.utils.render.RenderContext.drawTexture(ms, x - 3.5f, y + (h - size) / 2f - 1f,
                size, size, 5.5f, media.getTexture(), Color.WHITE);

        renderLabel(ms, media.title, x + 14f, y, h);
        renderWaveAnimation(ms, x, y, h, media);
    }

    private void renderWaveAnimation(MatrixStack ms, float baseX, float baseY, float h, MediaUtils.MediaInfo media) {
        Font font = FontsContext.REGULAR.getFont(9f);
        float trackW = font.getFont().getWidth(media.title, 9f);
        float textEndX = baseX + 11f + 4f + trackW + 4f;
        float groupW = 4 * (2.5f + 1f) - 1f;
        float centerX = textEndX + groupW / 2f;
        float waveY = baseY + h + 5f;

        for (WaveAnimation anim : waveAnimations) {
            if (anim.isFinished(anim.getDirection())) {
                if (anim.getDirection() == Direction.FORWARDS) {
                    anim.setDirection(Direction.BACKWARDS);
                } else {
                    anim.setValue(4 + Math.random() * 2);
                    anim.setMs(350 + (int)(Math.random() * 400));
                    anim.setDirection(Direction.FORWARDS);
                }
            }
        }

        Color waveColor = desaturate(MediaUtils.lastAlbumColor, 0.5f);
        for (int i = 0; i < 4; i++) {
            double half = waveAnimations[i].getOutput();
            float barX = centerX + (i - 2f) * 3.5f;
            ru.flow.base.utils.render.RenderContext.drawRound(barX + 3, waveY - (float)half - 11,
                    2.3f, (float)(half * 2), 0.7f, waveColor, ms);
        }
    }

    private void renderTime(MatrixStack ms, RenderContext ctx, float x, float y, float h) {
        float timeX = x - ctx.timeWidth - 6f;
        float timeY = y + (h - 9f) / 2f + 1f;
        ru.flow.base.utils.render.RenderContext.drawText(FontsContext.MEDIUM.getFont(9f),
                ctx.timeString, timeX - 3, timeY, ctx.timeColor.getRGB(), ms.peek().getPositionMatrix());
    }

    private void renderBackground(MatrixStack ms, float x, float y, float w, float h) {
        MediaUtils.MediaInfo media = MediaUtils.getCurrentMedia();
        Color bg = media != null && media.getTexture() != null
                ? desaturate(MediaUtils.lastAlbumColor, 0.5f)
                : new Color(0xFF464646, true);
        float blur = media != null && media.getTexture() != null ? 55f : 25f;

        ru.flow.base.utils.render.RenderContext.drawBlur(ms, x, y, w - 8, h - 2,
                new ColorState(bg), new RadiusState(8.5), 1f, blur);
    }

    private void renderStatusBox(MatrixStack ms, float x, float y, float h, Color color) {

        ru.flow.base.utils.render.RenderContext.drawRound(x - 1.5f, y + (h - 11f) / 2f - 1,
                11f, 11f, 4.5f, color, ms);
    }

    private void renderLabel(MatrixStack ms, String text, float x, float y, float h) {
        ru.flow.base.utils.render.RenderContext.drawText(FontsContext.MEDIUM.getFont(9f),
                text, x, y - 1f + (h - 9f) / 2f + 1.25f, Color.WHITE.getRGB(), ms.peek().getPositionMatrix());
    }

    private void renderBossBar(MatrixStack ms, ClientBossBar bar, float x, float y, float w, float h) {
        BossBarInfo info = extractBossBarInfo(bar);
        float timeBoxW = info.timeWidth + 10f;
        float totalW = timeBoxW + info.labelWidth;
        float cx = x + (w - totalW) / 2f;
        float ty = y - 9f - 4f;

        ru.flow.base.utils.render.RenderContext.drawRound(cx -5.5f, ty - 2f, timeBoxW, 11.5f, 3, COLOR_RED, ms);
        ru.flow.base.utils.render.RenderContext.drawText(FontsContext.MEDIUM.getFont(9f),
                info.timeString, cx - 1, ty, Color.WHITE.getRGB(), ms.peek().getPositionMatrix());
        ru.flow.base.utils.render.RenderContext.drawText(FontsContext.MEDIUM.getFont(9f),
                info.labelText, cx + timeBoxW - 3, ty, Color.WHITE.getRGB(), ms.peek().getPositionMatrix());
    }

    private void renderConnectionIndicator(MatrixStack ms, RenderContext ctx, float x, float y, float w, float h) {
        float ix = x + w;
        float iy = y + (h - 9f) / 2f - 3f;

        if (Interface.getInstance().conIcon.isSelected("Обычная")) {
            String symbol = mc.isInSingleplayer() ? "A" : "B";
            ru.flow.base.utils.render.RenderContext.drawText(FontsContext.ICF.getFont(12f),
                    symbol, ix, iy + 1.5f, ctx.timeColor.getRGB(), ms.peek().getPositionMatrix());
        } else if (Interface.getInstance().conIcon.isSelected("Продвинутая")) {
            if (mc.isInSingleplayer()) {
                ru.flow.base.utils.render.RenderContext.drawText(FontsContext.ICF.getFont(12f),
                        "A", ix, iy + 1.5f, ctx.timeColor.getRGB(), ms.peek().getPositionMatrix());
            } else {
                renderConnectionQuality(ms, ix, iy + 2f);
            }
        }
    }

    private void renderConnectionQuality(MatrixStack ms, float x, float y) {
        int ping = getPlayerPing();
        int white = ping <= 60 ? 4 : ping <= 80 ? 3 : ping <= 100 ? 2 : ping <= 120 ? 1 : 0;
        int[] heights = {4, 6, 8, 10};

        for (int i = 0; i < 4; i++) {
            Color c = i < white ? new Color(0xDDFFFFFF, true) : new Color(0x3DFFFFFF, true);
            float bh = heights[i];
            ru.flow.base.utils.render.RenderContext.drawRound(x + i * 3.3f, y + (10 - bh),
                    3f, bh, 0.2f, c, ms);
        }
    }

    private void animateDimensions(WatermarkContent content) {
        float w = content.width + 20f;
        float h = Math.max(20f, content.height + 8f);
        if (content.needsExtraHeight) h -= 1f;

        if (Math.abs(widthAnimation.getOutput() - w) > 0.5f) widthAnimation.animateTo(w);
        if (Math.abs(heightAnimation.getOutput() - h) > 0.5f) heightAnimation.animateTo(h);
    }

    private @Nullable ClientBossBar getPrimaryBossBar() {
        InGameHud hud = mc.inGameHud;
        BossBarHud bossBarHud = hud.getBossBarHud();
        Map<UUID, ClientBossBar> bars = bossBarHud.bossBars;
        return bars.isEmpty() ? null : bars.values().iterator().next();
    }


    private int getPlayerPing() {
        if (mc.player == null || mc.getNetworkHandler() == null) return 0;
        PlayerListEntry entry = mc.getNetworkHandler().getPlayerListEntry(mc.player.getUuid());
        return entry != null ? entry.getLatency() : 0;
    }

    private BossBarInfo extractBossBarInfo(ClientBossBar bar) {
        String raw = bar.getName().getString();
        Font font = FontsContext.REGULAR.getFont(9f);

        Pattern pattern = Pattern.compile("(\\d+)(?!.*\\d)");
        Matcher matcher = pattern.matcher(raw);
        String time = matcher.find() ? matcher.group(1) + "s" : "??s";

        String label = raw.replaceAll(",?\\s*до конца.*$", "")
                .replaceAll("Телепортация.*", "Телепортация").trim();

        return new BossBarInfo(time, label,
                font.getFont().getWidth(time, 9f),
                font.getFont().getWidth(label, 9f));
    }

    private float[] calculateBossBarSize(ClientBossBar bar) {
        BossBarInfo info = extractBossBarInfo(bar);
        return new float[] { info.timeWidth + 16f + info.labelWidth, 13f };
    }

    private Color desaturate(Color c, float factor) {
        float[] hsb = Color.RGBtoHSB(c.getRed(), c.getGreen(), c.getBlue(), null);
        hsb[1] *= factor;
        return new Color(Color.HSBtoRGB(hsb[0], hsb[1], hsb[2]));
    }

    public enum NotificationType {
        SUCCESS(new Color(0xFF46FF00, true)),
        ERROR(new Color(0xFFFF4242, true)),
        WARNING(new Color(0xFFFFAA00, true)),
        INFO(new Color(0xFF42A5FF, true)),
        DEFAULT(new Color(0xFFA442FF, true));

        public final Color color;
        NotificationType(Color color) { this.color = color; }
    }

    private enum ContentType { NOTIFICATION, BOSS_BAR, MEDIA, DEFAULT }

    private static class WatermarkContent {
        final ContentType type;
        final float width, height;
        final Object data;
        final boolean needsExtraHeight;

        WatermarkContent(ContentType type, float width, float height, Object data, boolean needsExtraHeight) {
            this.type = type;
            this.width = width;
            this.height = height;
            this.data = data;
            this.needsExtraHeight = needsExtraHeight;
        }
    }

    private static class RenderContext {
        final String timeString;
        final float timeWidth;
        final Color timeColor;

        RenderContext(int screenWidth) {
            Font font = FontsContext.REGULAR.getFont(9f);
            timeString = LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm"));
            timeWidth = font.getFont().getWidth(timeString, 9f);
            timeColor = Color.WHITE;
        }
    }

    private static class BossBarInfo {
        final String timeString, labelText;
        final float timeWidth, labelWidth;

        BossBarInfo(String timeString, String labelText, float timeWidth, float labelWidth) {
            this.timeString = timeString;
            this.labelText = labelText;
            this.timeWidth = timeWidth;
            this.labelWidth = labelWidth;
        }
    }

    private static class SimpleAnimation {
        private float current, target;
        private final long duration;
        private long start;
        private boolean running;

        SimpleAnimation(float val, long duration) {
            this.current = this.target = val;
            this.duration = duration;
        }

        void animateTo(float newTarget) {
            target = newTarget;
            start = System.currentTimeMillis();
            running = true;
        }

        float getOutput() {
            if (!running) return current;

            long elapsed = System.currentTimeMillis() - start;
            float progress = Math.min(1f, (float) elapsed / duration);
            current = current + progress * (target - current);

            if (progress >= 1f) {
                running = false;
                current = target;
            }
            return current;
        }
    }
}
MediaUtils:
Expand Collapse Copy
package ru.flow.api.media;

import by.bonenaut7.mediatransport4j.api.MediaSession;
import by.bonenaut7.mediatransport4j.api.MediaTransport;
import com.google.common.io.BaseEncoding;
import net.minecraft.client.texture.AbstractTexture;
import ru.flow.base.utils.render.Render2DUtil;
import ru.flow.base.utils.render.RenderContext;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.nio.ByteBuffer;
import java.security.MessageDigest;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class MediaUtils {

    private static boolean initialized = false;
    private static final ScheduledExecutorService s = Executors.newSingleThreadScheduledExecutor();
    private static volatile MediaInfo mediaInfo = null;
    public static volatile Color lastAlbumColor = Color.WHITE;

    private static final Map<String, AbstractTexture> textureCache = new ConcurrentHashMap<>();
    private static String previousHash = "";

    public static class MediaInfo {
        public final String title;
        public final String artist;
        public final String textureHash;

        public MediaInfo(String title, String artist, String textureHash) {
            this.title = title;
            this.artist = artist;
            this.textureHash = textureHash;
        }

        public AbstractTexture getTexture() {
            return textureCache.get(textureHash);
        }
    }

    public static MediaInfo getCurrentMedia() {
        if (!initialized) {
            boolean bb = MediaTransport.init();
            initialized = true;
            s.scheduleAtFixedRate(() -> {
                try {
                    List<MediaSession> sessions = MediaTransport.getMediaSessions();
                    if (sessions != null && !sessions.isEmpty()) {
                        final MediaSession mediaSession = sessions.get(0);

                        String hash = "";
                        AbstractTexture texture = null;

                        if (mediaSession.hasThumbnail()) {
                            ByteBuffer buf = mediaSession.getThumbnail();
                            hash = hashBuffer(buf);

                            if (!hash.equals(previousHash)) {
                                AbstractTexture old = textureCache.remove(previousHash);
                                if (old != null) old.close();

                                texture = convertTexture(buf);
                                if (texture != null) {
                                    textureCache.put(hash, texture);
                                }
                                previousHash = hash;
                            }
                        }

                        mediaInfo = new MediaInfo(mediaSession.getTitle(), mediaSession.getArtist(), hash);
                    } else {
                        clearCache();
                        mediaInfo = null;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }, 0, 50, TimeUnit.MILLISECONDS);
        }
        return mediaInfo;
    }

    public static Color getAverageColor(BufferedImage img) {
        long r = 0, g = 0, b = 0;
        int count = 0;

        int step = 5;
        for (int x = 0; x < img.getWidth(); x += step) {
            for (int y = 0; y < img.getHeight(); y += step) {
                int rgb = img.getRGB(x, y);
                r += (rgb >> 16) & 0xFF;
                g += (rgb >> 8) & 0xFF;
                b += (rgb) & 0xFF;
                count++;
            }
        }

        if (count == 0) return new Color(255, 255, 255);
        return new Color((int)(r / count), (int)(g / count), (int)(b / count));
    }

    private static AbstractTexture convertTexture(ByteBuffer buffer) {
        try {
            BufferedImage img = ImageIO.read(new ByteArrayInputStream(buffer.array()));
            if (img != null) {
                lastAlbumColor = getAverageColor(img);
                return RenderContext.convert(img);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }



    private static String hashBuffer(ByteBuffer buffer) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(buffer.array());
            return BaseEncoding.base16().lowerCase().encode(md.digest());
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    private static void clearCache() {
        textureCache.values().forEach(AbstractTexture::close);
        textureCache.clear();
        previousHash = "";
    }
}
дерьмо
 
Назад
Сверху Снизу