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

Вопрос Фикс Dynamic island

Начинающий
Начинающий
Статус
Оффлайн
Регистрация
30 Июл 2024
Сообщения
13
Реакции
0
package wtf.dettex.implement.features.draggables;

import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.network.PlayerListEntry;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.item.ItemStack;
import org.joml.Matrix4f;
import wtf.dettex.api.other.draggable.AbstractDraggable;
import wtf.dettex.api.system.font.FontRenderer;
import wtf.dettex.api.system.font.Fonts;
import wtf.dettex.api.system.shape.ShapeProperties;
import wtf.dettex.common.util.color.ColorUtil;
import wtf.dettex.common.util.other.Instance;
import wtf.dettex.modules.impl.render.Hud;

import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayDeque;
import java.util.Queue;

public class DynamicIsland extends AbstractDraggable {
private static final long SHOW_MS = 2200L;

public enum NotificationType {
SUCCESS(0x4AE54A),
ERROR(0xFF4545),
WARNING(0xFFB830),
INFO(0x4AADFF),
DEFAULT(0xA855F7);

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

private record Notif(String text, int color) {}

private static volatile Notif active = null;
private static volatile long activeEnd = 0L;
private static final Queue<Notif> queue = new ArrayDeque<>();

public static DynamicIsland getInstance() {
return Instance.getDraggable(DynamicIsland.class);
}

public static void addNotification(String text, NotificationType type) {
Notif n = new Notif(text, type.color);
if (active == null || System.currentTimeMillis() >= activeEnd) {
active = n;
activeEnd = System.currentTimeMillis() + SHOW_MS;
} else {
queue.offer(n);
}
}

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

public static void strengthNotification() {
if (mc.player == null) return;
EquipmentSlot[] slots = {EquipmentSlot.HEAD, EquipmentSlot.CHEST,
EquipmentSlot.LEGS, EquipmentSlot.FEET};
String[] names = {"Шлем", "Нагрудник", "Поножи", "Ботинки"};
for (int i = 0; i < slots.length; i++) {
ItemStack s = mc.player.getEquippedStack(slots);
if (s.isEmpty() || !s.isDamageable()) continue;
float pct = (float)(s.getMaxDamage() - s.getDamage()) / s.getMaxDamage();
if (pct <= 0.1f && pct > 0f)
addNotification(names + " имеет низкую прочность!", NotificationType.WARNING);
}
}

private static final int BG = ColorUtil.getColor(18, 18, 22, 220);
private static final int BG_DARK = ColorUtil.getColor(12, 12, 16, 220);

private float pillW = 100f;
private static final float PILL_H = 22f;

private final float[] waveH = {4f, 8f, 5f, 9f};
private final float[] waveDir = {1f, -1f, 1f, -1f};
private final float[] waveSpd = {0.18f, 0.22f, 0.15f, 0.20f};

public DynamicIsland() {
super("Dynamic Island", 10, 10, 100, 22, false);
}

@override
public void tick() {
if (active != null && System.currentTimeMillis() >= activeEnd) {
Notif next = queue.poll();
active = next;
activeEnd = next != null ? System.currentTimeMillis() + SHOW_MS : 0L;
}

for (int i = 0; i < 4; i++) {
waveH += waveDir * waveSpd;
if (waveH >= 10f) {
waveH = 10f;
waveDir = -1f;
waveSpd = 0.12f + (float)(Math.random() * 0.18f);
}
if (waveH <= 3f) {
waveH = 3f;
waveDir = 1f;
waveSpd = 0.12f + (float)(Math.random() * 0.18f);
}
}
}

@override
public void drawDraggable(DrawContext context) {
if (mc.player == null || mc.world == null) return;

Hud hud = Hud.getInstance();
if (hud == null || !hud.interfaceSettings.isSelected("Dynamic Island")) {
return;
}

MatrixStack ms = context.getMatrices();
int sw = window.getScaledWidth();

boolean hasNotif = active != null && System.currentTimeMillis() < activeEnd;

// Media info - временно отключено, так как нет MediaUtils в проекте
boolean hasMedia = false;
String mediaTitle = "";

String time = LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm"));
FontRenderer fontTime = Fonts.getSize(12, Fonts.Type.BOLD);
FontRenderer fontName = Fonts.getSize(13, Fonts.Type.BOLD);
FontRenderer fontRegular = Fonts.getSize(11, Fonts.Type.DEFAULT);

float timeW = fontTime.getStringWidth(time);

float targetW;
if (hasNotif) {
float tw = fontRegular.getStringWidth(active.text());
targetW = 12f + 7f + 5f + tw + 12f;
} else if (hasMedia) {
String t = trimTitle(mediaTitle);
float tw = fontRegular.getStringWidth(t);
targetW = 12f + tw + 8f + waveGroupW() + 12f;
} else {
float nameW = fontName.getStringWidth(getDisplayName());
targetW = 12f + 12f + 4f + nameW + 12f; // 12f для кружочка + 4f отступ
}

pillW += (targetW - pillW) * 0.18f;

float pingGroupW = 4 * 3.8f + 3f;
float totalW = timeW + 8f + pillW + 8f + pingGroupW;
float startX = sw / 2f - totalW / 2f;
float pillX = startX + timeW + 8f;
float pillY = 5f;
float midY = pillY + PILL_H / 2f;
float textY = pillY + (PILL_H - fontName.getStringHeight(getDisplayName())) / 2f;
float timeY = pillY + (PILL_H - fontTime.getStringHeight(time)) / 2f;

// Время - отцентрировано по вертикали с островком
fontTime.drawString(ms, time, startX, timeY, ColorUtil.getText());

blurGlass.render(ShapeProperties.create(ms, pillX, pillY, pillW, PILL_H)
.round(PILL_H / 2f)
.color(BG)
.build());

rectangle.render(ShapeProperties.create(ms, pillX, pillY, pillW, PILL_H)
.round(PILL_H / 2f)
.thickness(0.15f)
.outlineColor(ColorUtil.getColor(255, 255, 255, 18))
.color(BG, BG_DARK, BG_DARK, BG)
.build());

float cx = pillX + 12f;

if (hasNotif) {
float dotR = 4f;
rectangle.render(ShapeProperties.create(ms, cx, midY - dotR, dotR * 2f, dotR * 2f)
.round(dotR)
.color(active.color())
.build());
cx += dotR * 2f + 6f;
fontRegular.drawString(ms, active.text(), cx, textY, ColorUtil.getText());
} else if (hasMedia) {
String t = trimTitle(mediaTitle);
fontRegular.drawString(ms, t, cx, textY, ColorUtil.getText());
cx += fontRegular.getStringWidth(t) + 8f;
renderWaveBars(ms, cx, midY);
} else {
renderCircle(ms, cx, midY - 5f, ColorUtil.getClientColor());
cx += 12f;
fontName.drawString(ms, getDisplayName(), cx, textY, ColorUtil.getClientColor());
}

float barsX = pillX + pillW + 8f;
float barsY = midY - 12f / 2f;
renderPing(ms, barsX, barsY);

setX((int) pillX);
setY((int) pillY);
setWidth((int) pillW);
setHeight((int) PILL_H);
}

private void renderWaveBars(MatrixStack ms, float x, float midY) {
int color = ColorUtil.getText(0.9f);
for (int i = 0; i < 4; i++) {
float bh = waveH;
rectangle.render(ShapeProperties.create(ms, x + i * 5f, midY - bh / 2f, 3f, bh)
.round(1.2f)
.color(color)
.build());
}
}

private float waveGroupW() {
return 4 * 3f + 3 * 2f;
}

private void renderPing(MatrixStack ms, float x, float y) {
int ping = getPlayerPing();
int lit = ping <= 50 ? 4 : ping <= 80 ? 3 : ping <= 120 ? 2 : ping <= 180 ? 1 : 0;
int[] maxH = {5, 7, 9, 12};
long t = System.currentTimeMillis();

for (int i = 0; i < 4; i++) {
float breath = (float)(Math.sin(t / 600.0 + i * 0.7) * 0.5 + 0.5);
float bh = i < lit ? maxH * (0.6f + 0.4f * breath) : maxH * (0.25f + 0.1f * breath);
int col = i < lit ? ColorUtil.getText(0.85f) : ColorUtil.getText(0.18f);

rectangle.render(ShapeProperties.create(ms, x + i * 3.8f, y + (12 - bh), 3.2f, bh)
.round(1.2f)
.color(col)
.build());
}
}

private void renderCircle(MatrixStack ms, float x, float y, int color) {
float radius = 5f;
rectangle.render(ShapeProperties.create(ms, x, y, radius * 2f, radius * 2f)
.round(radius)
.color(color)
.build());
}

private String trimTitle(String s) {
return s.length() > 22 ? s.substring(0, 20) + "…" : s;
}

private String getDisplayName() {
return "Pasta";
}

private int getPlayerPing() {
if (mc.player == null || mc.getNetworkHandler() == null) return 0;
PlayerListEntry e = mc.getNetworkHandler().getPlayerListEntry(mc.player.getUuid());
return e != null ? e.getLatency() : 0;
}
} такой островок сделала мне нейронка,выглядит убого, помогите исправить
 

Вложения

  • IMG_4689.png
    IMG_4689.png
    17.1 KB · Просмотры: 52
package wtf.dettex.implement.features.draggables;

import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.network.PlayerListEntry;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.item.ItemStack;
import org.joml.Matrix4f;
import wtf.dettex.api.other.draggable.AbstractDraggable;
import wtf.dettex.api.system.font.FontRenderer;
import wtf.dettex.api.system.font.Fonts;
import wtf.dettex.api.system.shape.ShapeProperties;
import wtf.dettex.common.util.color.ColorUtil;
import wtf.dettex.common.util.other.Instance;
import wtf.dettex.modules.impl.render.Hud;

import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayDeque;
import java.util.Queue;

public class DynamicIsland extends AbstractDraggable {
private static final long SHOW_MS = 2200L;

public enum NotificationType {
SUCCESS(0x4AE54A),
ERROR(0xFF4545),
WARNING(0xFFB830),
INFO(0x4AADFF),
DEFAULT(0xA855F7);

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

private record Notif(String text, int color) {}

private static volatile Notif active = null;
private static volatile long activeEnd = 0L;
private static final Queue<Notif> queue = new ArrayDeque<>();

public static DynamicIsland getInstance() {
return Instance.getDraggable(DynamicIsland.class);
}

public static void addNotification(String text, NotificationType type) {
Notif n = new Notif(text, type.color);
if (active == null || System.currentTimeMillis() >= activeEnd) {
active = n;
activeEnd = System.currentTimeMillis() + SHOW_MS;
} else {
queue.offer(n);
}
}

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

public static void strengthNotification() {
if (mc.player == null) return;
EquipmentSlot[] slots = {EquipmentSlot.HEAD, EquipmentSlot.CHEST,
EquipmentSlot.LEGS, EquipmentSlot.FEET};
String[] names = {"Шлем", "Нагрудник", "Поножи", "Ботинки"};
for (int i = 0; i < slots.length; i++) {
ItemStack s = mc.player.getEquippedStack(slots);
if (s.isEmpty() || !s.isDamageable()) continue;
float pct = (float)(s.getMaxDamage() - s.getDamage()) / s.getMaxDamage();
if (pct <= 0.1f && pct > 0f)
addNotification(names + " имеет низкую прочность!", NotificationType.WARNING);
}
}

private static final int BG = ColorUtil.getColor(18, 18, 22, 220);
private static final int BG_DARK = ColorUtil.getColor(12, 12, 16, 220);

private float pillW = 100f;
private static final float PILL_H = 22f;

private final float[] waveH = {4f, 8f, 5f, 9f};
private final float[] waveDir = {1f, -1f, 1f, -1f};
private final float[] waveSpd = {0.18f, 0.22f, 0.15f, 0.20f};

public DynamicIsland() {
super("Dynamic Island", 10, 10, 100, 22, false);
}

@override
public void tick() {
if (active != null && System.currentTimeMillis() >= activeEnd) {
Notif next = queue.poll();
active = next;
activeEnd = next != null ? System.currentTimeMillis() + SHOW_MS : 0L;
}

for (int i = 0; i < 4; i++) {
waveH += waveDir * waveSpd;
if (waveH >= 10f) {
waveH = 10f;
waveDir = -1f;
waveSpd = 0.12f + (float)(Math.random() * 0.18f);
}
if (waveH <= 3f) {
waveH = 3f;
waveDir = 1f;
waveSpd = 0.12f + (float)(Math.random() * 0.18f);
}
}
}

@override
public void drawDraggable(DrawContext context) {
if (mc.player == null || mc.world == null) return;

Hud hud = Hud.getInstance();
if (hud == null || !hud.interfaceSettings.isSelected("Dynamic Island")) {
return;
}

MatrixStack ms = context.getMatrices();
int sw = window.getScaledWidth();

boolean hasNotif = active != null && System.currentTimeMillis() < activeEnd;

// Media info - временно отключено, так как нет MediaUtils в проекте
boolean hasMedia = false;
String mediaTitle = "";

String time = LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm"));
FontRenderer fontTime = Fonts.getSize(12, Fonts.Type.BOLD);
FontRenderer fontName = Fonts.getSize(13, Fonts.Type.BOLD);
FontRenderer fontRegular = Fonts.getSize(11, Fonts.Type.DEFAULT);

float timeW = fontTime.getStringWidth(time);

float targetW;
if (hasNotif) {
float tw = fontRegular.getStringWidth(active.text());
targetW = 12f + 7f + 5f + tw + 12f;
} else if (hasMedia) {
String t = trimTitle(mediaTitle);
float tw = fontRegular.getStringWidth(t);
targetW = 12f + tw + 8f + waveGroupW() + 12f;
} else {
float nameW = fontName.getStringWidth(getDisplayName());
targetW = 12f + 12f + 4f + nameW + 12f; // 12f для кружочка + 4f отступ
}

pillW += (targetW - pillW) * 0.18f;

float pingGroupW = 4 * 3.8f + 3f;
float totalW = timeW + 8f + pillW + 8f + pingGroupW;
float startX = sw / 2f - totalW / 2f;
float pillX = startX + timeW + 8f;
float pillY = 5f;
float midY = pillY + PILL_H / 2f;
float textY = pillY + (PILL_H - fontName.getStringHeight(getDisplayName())) / 2f;
float timeY = pillY + (PILL_H - fontTime.getStringHeight(time)) / 2f;

// Время - отцентрировано по вертикали с островком
fontTime.drawString(ms, time, startX, timeY, ColorUtil.getText());

blurGlass.render(ShapeProperties.create(ms, pillX, pillY, pillW, PILL_H)
.round(PILL_H / 2f)
.color(BG)
.build());

rectangle.render(ShapeProperties.create(ms, pillX, pillY, pillW, PILL_H)
.round(PILL_H / 2f)
.thickness(0.15f)
.outlineColor(ColorUtil.getColor(255, 255, 255, 18))
.color(BG, BG_DARK, BG_DARK, BG)
.build());

float cx = pillX + 12f;

if (hasNotif) {
float dotR = 4f;
rectangle.render(ShapeProperties.create(ms, cx, midY - dotR, dotR * 2f, dotR * 2f)
.round(dotR)
.color(active.color())
.build());
cx += dotR * 2f + 6f;
fontRegular.drawString(ms, active.text(), cx, textY, ColorUtil.getText());
} else if (hasMedia) {
String t = trimTitle(mediaTitle);
fontRegular.drawString(ms, t, cx, textY, ColorUtil.getText());
cx += fontRegular.getStringWidth(t) + 8f;
renderWaveBars(ms, cx, midY);
} else {
renderCircle(ms, cx, midY - 5f, ColorUtil.getClientColor());
cx += 12f;
fontName.drawString(ms, getDisplayName(), cx, textY, ColorUtil.getClientColor());
}

float barsX = pillX + pillW + 8f;
float barsY = midY - 12f / 2f;
renderPing(ms, barsX, barsY);

setX((int) pillX);
setY((int) pillY);
setWidth((int) pillW);
setHeight((int) PILL_H);
}

private void renderWaveBars(MatrixStack ms, float x, float midY) {
int color = ColorUtil.getText(0.9f);
for (int i = 0; i < 4; i++) {
float bh = waveH;
rectangle.render(ShapeProperties.create(ms, x + i * 5f, midY - bh / 2f, 3f, bh)
.round(1.2f)
.color(color)
.build());
}
}

private float waveGroupW() {
return 4 * 3f + 3 * 2f;
}

private void renderPing(MatrixStack ms, float x, float y) {
int ping = getPlayerPing();
int lit = ping <= 50 ? 4 : ping <= 80 ? 3 : ping <= 120 ? 2 : ping <= 180 ? 1 : 0;
int[] maxH = {5, 7, 9, 12};
long t = System.currentTimeMillis();

for (int i = 0; i < 4; i++) {
float breath = (float)(Math.sin(t / 600.0 + i * 0.7) * 0.5 + 0.5);
float bh = i < lit ? maxH * (0.6f + 0.4f * breath) : maxH * (0.25f + 0.1f * breath);
int col = i < lit ? ColorUtil.getText(0.85f) : ColorUtil.getText(0.18f);

rectangle.render(ShapeProperties.create(ms, x + i * 3.8f, y + (12 - bh), 3.2f, bh)
.round(1.2f)
.color(col)
.build());
}
}

private void renderCircle(MatrixStack ms, float x, float y, int color) {
float radius = 5f;
rectangle.render(ShapeProperties.create(ms, x, y, radius * 2f, radius * 2f)
.round(radius)
.color(color)
.build());
}

private String trimTitle(String s) {
return s.length() > 22 ? s.substring(0, 20) + "…" : s;
}

private String getDisplayName() {
return "Pasta";
}

private int getPlayerPing() {
if (mc.player == null || mc.getNetworkHandler() == null) return 0;
PlayerListEntry e = mc.getNetworkHandler().getPlayerListEntry(mc.player.getUuid());
return e != null ? e.getLatency() : 0;
}
} такой островок сделала мне нейронка,выглядит убого, помогите исправить
В роблокс иди дальше играй, брейнротов лови, не твоё это братан...
 
package wtf.dettex.implement.features.draggables;

import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.network.PlayerListEntry;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.item.ItemStack;
import org.joml.Matrix4f;
import wtf.dettex.api.other.draggable.AbstractDraggable;
import wtf.dettex.api.system.font.FontRenderer;
import wtf.dettex.api.system.font.Fonts;
import wtf.dettex.api.system.shape.ShapeProperties;
import wtf.dettex.common.util.color.ColorUtil;
import wtf.dettex.common.util.other.Instance;
import wtf.dettex.modules.impl.render.Hud;

import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayDeque;
import java.util.Queue;

public class DynamicIsland extends AbstractDraggable {
private static final long SHOW_MS = 2200L;

public enum NotificationType {
SUCCESS(0x4AE54A),
ERROR(0xFF4545),
WARNING(0xFFB830),
INFO(0x4AADFF),
DEFAULT(0xA855F7);

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

private record Notif(String text, int color) {}

private static volatile Notif active = null;
private static volatile long activeEnd = 0L;
private static final Queue<Notif> queue = new ArrayDeque<>();

public static DynamicIsland getInstance() {
return Instance.getDraggable(DynamicIsland.class);
}

public static void addNotification(String text, NotificationType type) {
Notif n = new Notif(text, type.color);
if (active == null || System.currentTimeMillis() >= activeEnd) {
active = n;
activeEnd = System.currentTimeMillis() + SHOW_MS;
} else {
queue.offer(n);
}
}

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

public static void strengthNotification() {
if (mc.player == null) return;
EquipmentSlot[] slots = {EquipmentSlot.HEAD, EquipmentSlot.CHEST,
EquipmentSlot.LEGS, EquipmentSlot.FEET};
String[] names = {"Шлем", "Нагрудник", "Поножи", "Ботинки"};
for (int i = 0; i < slots.length; i++) {
ItemStack s = mc.player.getEquippedStack(slots);
if (s.isEmpty() || !s.isDamageable()) continue;
float pct = (float)(s.getMaxDamage() - s.getDamage()) / s.getMaxDamage();
if (pct <= 0.1f && pct > 0f)
addNotification(names + " имеет низкую прочность!", NotificationType.WARNING);
}
}

private static final int BG = ColorUtil.getColor(18, 18, 22, 220);
private static final int BG_DARK = ColorUtil.getColor(12, 12, 16, 220);

private float pillW = 100f;
private static final float PILL_H = 22f;

private final float[] waveH = {4f, 8f, 5f, 9f};
private final float[] waveDir = {1f, -1f, 1f, -1f};
private final float[] waveSpd = {0.18f, 0.22f, 0.15f, 0.20f};

public DynamicIsland() {
super("Dynamic Island", 10, 10, 100, 22, false);
}

@override
public void tick() {
if (active != null && System.currentTimeMillis() >= activeEnd) {
Notif next = queue.poll();
active = next;
activeEnd = next != null ? System.currentTimeMillis() + SHOW_MS : 0L;
}

for (int i = 0; i < 4; i++) {
waveH += waveDir * waveSpd;
if (waveH >= 10f) {
waveH = 10f;
waveDir = -1f;
waveSpd = 0.12f + (float)(Math.random() * 0.18f);
}
if (waveH <= 3f) {
waveH = 3f;
waveDir = 1f;
waveSpd = 0.12f + (float)(Math.random() * 0.18f);
}
}
}

@override
public void drawDraggable(DrawContext context) {
if (mc.player == null || mc.world == null) return;

Hud hud = Hud.getInstance();
if (hud == null || !hud.interfaceSettings.isSelected("Dynamic Island")) {
return;
}

MatrixStack ms = context.getMatrices();
int sw = window.getScaledWidth();

boolean hasNotif = active != null && System.currentTimeMillis() < activeEnd;

// Media info - временно отключено, так как нет MediaUtils в проекте
boolean hasMedia = false;
String mediaTitle = "";

String time = LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm"));
FontRenderer fontTime = Fonts.getSize(12, Fonts.Type.BOLD);
FontRenderer fontName = Fonts.getSize(13, Fonts.Type.BOLD);
FontRenderer fontRegular = Fonts.getSize(11, Fonts.Type.DEFAULT);

float timeW = fontTime.getStringWidth(time);

float targetW;
if (hasNotif) {
float tw = fontRegular.getStringWidth(active.text());
targetW = 12f + 7f + 5f + tw + 12f;
} else if (hasMedia) {
String t = trimTitle(mediaTitle);
float tw = fontRegular.getStringWidth(t);
targetW = 12f + tw + 8f + waveGroupW() + 12f;
} else {
float nameW = fontName.getStringWidth(getDisplayName());
targetW = 12f + 12f + 4f + nameW + 12f; // 12f для кружочка + 4f отступ
}

pillW += (targetW - pillW) * 0.18f;

float pingGroupW = 4 * 3.8f + 3f;
float totalW = timeW + 8f + pillW + 8f + pingGroupW;
float startX = sw / 2f - totalW / 2f;
float pillX = startX + timeW + 8f;
float pillY = 5f;
float midY = pillY + PILL_H / 2f;
float textY = pillY + (PILL_H - fontName.getStringHeight(getDisplayName())) / 2f;
float timeY = pillY + (PILL_H - fontTime.getStringHeight(time)) / 2f;

// Время - отцентрировано по вертикали с островком
fontTime.drawString(ms, time, startX, timeY, ColorUtil.getText());

blurGlass.render(ShapeProperties.create(ms, pillX, pillY, pillW, PILL_H)
.round(PILL_H / 2f)
.color(BG)
.build());

rectangle.render(ShapeProperties.create(ms, pillX, pillY, pillW, PILL_H)
.round(PILL_H / 2f)
.thickness(0.15f)
.outlineColor(ColorUtil.getColor(255, 255, 255, 18))
.color(BG, BG_DARK, BG_DARK, BG)
.build());

float cx = pillX + 12f;

if (hasNotif) {
float dotR = 4f;
rectangle.render(ShapeProperties.create(ms, cx, midY - dotR, dotR * 2f, dotR * 2f)
.round(dotR)
.color(active.color())
.build());
cx += dotR * 2f + 6f;
fontRegular.drawString(ms, active.text(), cx, textY, ColorUtil.getText());
} else if (hasMedia) {
String t = trimTitle(mediaTitle);
fontRegular.drawString(ms, t, cx, textY, ColorUtil.getText());
cx += fontRegular.getStringWidth(t) + 8f;
renderWaveBars(ms, cx, midY);
} else {
renderCircle(ms, cx, midY - 5f, ColorUtil.getClientColor());
cx += 12f;
fontName.drawString(ms, getDisplayName(), cx, textY, ColorUtil.getClientColor());
}

float barsX = pillX + pillW + 8f;
float barsY = midY - 12f / 2f;
renderPing(ms, barsX, barsY);

setX((int) pillX);
setY((int) pillY);
setWidth((int) pillW);
setHeight((int) PILL_H);
}

private void renderWaveBars(MatrixStack ms, float x, float midY) {
int color = ColorUtil.getText(0.9f);
for (int i = 0; i < 4; i++) {
float bh = waveH;
rectangle.render(ShapeProperties.create(ms, x + i * 5f, midY - bh / 2f, 3f, bh)
.round(1.2f)
.color(color)
.build());
}
}

private float waveGroupW() {
return 4 * 3f + 3 * 2f;
}

private void renderPing(MatrixStack ms, float x, float y) {
int ping = getPlayerPing();
int lit = ping <= 50 ? 4 : ping <= 80 ? 3 : ping <= 120 ? 2 : ping <= 180 ? 1 : 0;
int[] maxH = {5, 7, 9, 12};
long t = System.currentTimeMillis();

for (int i = 0; i < 4; i++) {
float breath = (float)(Math.sin(t / 600.0 + i * 0.7) * 0.5 + 0.5);
float bh = i < lit ? maxH * (0.6f + 0.4f * breath) : maxH * (0.25f + 0.1f * breath);
int col = i < lit ? ColorUtil.getText(0.85f) : ColorUtil.getText(0.18f);

rectangle.render(ShapeProperties.create(ms, x + i * 3.8f, y + (12 - bh), 3.2f, bh)
.round(1.2f)
.color(col)
.build());
}
}

private void renderCircle(MatrixStack ms, float x, float y, int color) {
float radius = 5f;
rectangle.render(ShapeProperties.create(ms, x, y, radius * 2f, radius * 2f)
.round(radius)
.color(color)
.build());
}

private String trimTitle(String s) {
return s.length() > 22 ? s.substring(0, 20) + "…" : s;
}

private String getDisplayName() {
return "Pasta";
}

private int getPlayerPing() {
if (mc.player == null || mc.getNetworkHandler() == null) return 0;
PlayerListEntry e = mc.getNetworkHandler().getPlayerListEntry(mc.player.getUuid());
return e != null ? e.getLatency() : 0;
}
} такой островок сделала мне нейронка,выглядит убого, помогите исправить
Могу в тг помочь
 
package wtf.dettex.implement.features.draggables;

import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.network.PlayerListEntry;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.item.ItemStack;
import org.joml.Matrix4f;
import wtf.dettex.api.other.draggable.AbstractDraggable;
import wtf.dettex.api.system.font.FontRenderer;
import wtf.dettex.api.system.font.Fonts;
import wtf.dettex.api.system.shape.ShapeProperties;
import wtf.dettex.common.util.color.ColorUtil;
import wtf.dettex.common.util.other.Instance;
import wtf.dettex.modules.impl.render.Hud;

import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayDeque;
import java.util.Queue;

public class DynamicIsland extends AbstractDraggable {
private static final long SHOW_MS = 2200L;

public enum NotificationType {
SUCCESS(0x4AE54A),
ERROR(0xFF4545),
WARNING(0xFFB830),
INFO(0x4AADFF),
DEFAULT(0xA855F7);

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

private record Notif(String text, int color) {}

private static volatile Notif active = null;
private static volatile long activeEnd = 0L;
private static final Queue<Notif> queue = new ArrayDeque<>();

public static DynamicIsland getInstance() {
return Instance.getDraggable(DynamicIsland.class);
}

public static void addNotification(String text, NotificationType type) {
Notif n = new Notif(text, type.color);
if (active == null || System.currentTimeMillis() >= activeEnd) {
active = n;
activeEnd = System.currentTimeMillis() + SHOW_MS;
} else {
queue.offer(n);
}
}

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

public static void strengthNotification() {
if (mc.player == null) return;
EquipmentSlot[] slots = {EquipmentSlot.HEAD, EquipmentSlot.CHEST,
EquipmentSlot.LEGS, EquipmentSlot.FEET};
String[] names = {"Шлем", "Нагрудник", "Поножи", "Ботинки"};
for (int i = 0; i < slots.length; i++) {
ItemStack s = mc.player.getEquippedStack(slots);
if (s.isEmpty() || !s.isDamageable()) continue;
float pct = (float)(s.getMaxDamage() - s.getDamage()) / s.getMaxDamage();
if (pct <= 0.1f && pct > 0f)
addNotification(names + " имеет низкую прочность!", NotificationType.WARNING);
}
}

private static final int BG = ColorUtil.getColor(18, 18, 22, 220);
private static final int BG_DARK = ColorUtil.getColor(12, 12, 16, 220);

private float pillW = 100f;
private static final float PILL_H = 22f;

private final float[] waveH = {4f, 8f, 5f, 9f};
private final float[] waveDir = {1f, -1f, 1f, -1f};
private final float[] waveSpd = {0.18f, 0.22f, 0.15f, 0.20f};

public DynamicIsland() {
super("Dynamic Island", 10, 10, 100, 22, false);
}

@override
public void tick() {
if (active != null && System.currentTimeMillis() >= activeEnd) {
Notif next = queue.poll();
active = next;
activeEnd = next != null ? System.currentTimeMillis() + SHOW_MS : 0L;
}

for (int i = 0; i < 4; i++) {
waveH += waveDir * waveSpd;
if (waveH >= 10f) {
waveH = 10f;
waveDir = -1f;
waveSpd = 0.12f + (float)(Math.random() * 0.18f);
}
if (waveH <= 3f) {
waveH = 3f;
waveDir = 1f;
waveSpd = 0.12f + (float)(Math.random() * 0.18f);
}
}
}

@override
public void drawDraggable(DrawContext context) {
if (mc.player == null || mc.world == null) return;

Hud hud = Hud.getInstance();
if (hud == null || !hud.interfaceSettings.isSelected("Dynamic Island")) {
return;
}

MatrixStack ms = context.getMatrices();
int sw = window.getScaledWidth();

boolean hasNotif = active != null && System.currentTimeMillis() < activeEnd;

// Media info - временно отключено, так как нет MediaUtils в проекте
boolean hasMedia = false;
String mediaTitle = "";

String time = LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm"));
FontRenderer fontTime = Fonts.getSize(12, Fonts.Type.BOLD);
FontRenderer fontName = Fonts.getSize(13, Fonts.Type.BOLD);
FontRenderer fontRegular = Fonts.getSize(11, Fonts.Type.DEFAULT);

float timeW = fontTime.getStringWidth(time);

float targetW;
if (hasNotif) {
float tw = fontRegular.getStringWidth(active.text());
targetW = 12f + 7f + 5f + tw + 12f;
} else if (hasMedia) {
String t = trimTitle(mediaTitle);
float tw = fontRegular.getStringWidth(t);
targetW = 12f + tw + 8f + waveGroupW() + 12f;
} else {
float nameW = fontName.getStringWidth(getDisplayName());
targetW = 12f + 12f + 4f + nameW + 12f; // 12f для кружочка + 4f отступ
}

pillW += (targetW - pillW) * 0.18f;

float pingGroupW = 4 * 3.8f + 3f;
float totalW = timeW + 8f + pillW + 8f + pingGroupW;
float startX = sw / 2f - totalW / 2f;
float pillX = startX + timeW + 8f;
float pillY = 5f;
float midY = pillY + PILL_H / 2f;
float textY = pillY + (PILL_H - fontName.getStringHeight(getDisplayName())) / 2f;
float timeY = pillY + (PILL_H - fontTime.getStringHeight(time)) / 2f;

// Время - отцентрировано по вертикали с островком
fontTime.drawString(ms, time, startX, timeY, ColorUtil.getText());

blurGlass.render(ShapeProperties.create(ms, pillX, pillY, pillW, PILL_H)
.round(PILL_H / 2f)
.color(BG)
.build());

rectangle.render(ShapeProperties.create(ms, pillX, pillY, pillW, PILL_H)
.round(PILL_H / 2f)
.thickness(0.15f)
.outlineColor(ColorUtil.getColor(255, 255, 255, 18))
.color(BG, BG_DARK, BG_DARK, BG)
.build());

float cx = pillX + 12f;

if (hasNotif) {
float dotR = 4f;
rectangle.render(ShapeProperties.create(ms, cx, midY - dotR, dotR * 2f, dotR * 2f)
.round(dotR)
.color(active.color())
.build());
cx += dotR * 2f + 6f;
fontRegular.drawString(ms, active.text(), cx, textY, ColorUtil.getText());
} else if (hasMedia) {
String t = trimTitle(mediaTitle);
fontRegular.drawString(ms, t, cx, textY, ColorUtil.getText());
cx += fontRegular.getStringWidth(t) + 8f;
renderWaveBars(ms, cx, midY);
} else {
renderCircle(ms, cx, midY - 5f, ColorUtil.getClientColor());
cx += 12f;
fontName.drawString(ms, getDisplayName(), cx, textY, ColorUtil.getClientColor());
}

float barsX = pillX + pillW + 8f;
float barsY = midY - 12f / 2f;
renderPing(ms, barsX, barsY);

setX((int) pillX);
setY((int) pillY);
setWidth((int) pillW);
setHeight((int) PILL_H);
}

private void renderWaveBars(MatrixStack ms, float x, float midY) {
int color = ColorUtil.getText(0.9f);
for (int i = 0; i < 4; i++) {
float bh = waveH;
rectangle.render(ShapeProperties.create(ms, x + i * 5f, midY - bh / 2f, 3f, bh)
.round(1.2f)
.color(color)
.build());
}
}

private float waveGroupW() {
return 4 * 3f + 3 * 2f;
}

private void renderPing(MatrixStack ms, float x, float y) {
int ping = getPlayerPing();
int lit = ping <= 50 ? 4 : ping <= 80 ? 3 : ping <= 120 ? 2 : ping <= 180 ? 1 : 0;
int[] maxH = {5, 7, 9, 12};
long t = System.currentTimeMillis();

for (int i = 0; i < 4; i++) {
float breath = (float)(Math.sin(t / 600.0 + i * 0.7) * 0.5 + 0.5);
float bh = i < lit ? maxH * (0.6f + 0.4f * breath) : maxH * (0.25f + 0.1f * breath);
int col = i < lit ? ColorUtil.getText(0.85f) : ColorUtil.getText(0.18f);

rectangle.render(ShapeProperties.create(ms, x + i * 3.8f, y + (12 - bh), 3.2f, bh)
.round(1.2f)
.color(col)
.build());
}
}

private void renderCircle(MatrixStack ms, float x, float y, int color) {
float radius = 5f;
rectangle.render(ShapeProperties.create(ms, x, y, radius * 2f, radius * 2f)
.round(radius)
.color(color)
.build());
}

private String trimTitle(String s) {
return s.length() > 22 ? s.substring(0, 20) + "…" : s;
}

private String getDisplayName() {
return "Pasta";
}

private int getPlayerPing() {
if (mc.player == null || mc.getNetworkHandler() == null) return 0;
PlayerListEntry e = mc.getNetworkHandler().getPlayerListEntry(mc.player.getUuid());
return e != null ? e.getLatency() : 0;
}
} такой островок сделала мне нейронка,выглядит убого, помогите исправить
давай ещё всю визуалку за тебя писать будем
 
Скрытое содержимоеБро если не хочешь ему помогать то не пиши ты когда то таким же был
я не просил за себя придумать/писать визуал..
иди гайдик глянь как под хайд отвечать
 
package wtf.dettex.implement.features.draggables;

import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.network.PlayerListEntry;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.item.ItemStack;
import org.joml.Matrix4f;
import wtf.dettex.api.other.draggable.AbstractDraggable;
import wtf.dettex.api.system.font.FontRenderer;
import wtf.dettex.api.system.font.Fonts;
import wtf.dettex.api.system.shape.ShapeProperties;
import wtf.dettex.common.util.color.ColorUtil;
import wtf.dettex.common.util.other.Instance;
import wtf.dettex.modules.impl.render.Hud;

import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayDeque;
import java.util.Queue;

public class DynamicIsland extends AbstractDraggable {
private static final long SHOW_MS = 2200L;

public enum NotificationType {
SUCCESS(0x4AE54A),
ERROR(0xFF4545),
WARNING(0xFFB830),
INFO(0x4AADFF),
DEFAULT(0xA855F7);

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

private record Notif(String text, int color) {}

private static volatile Notif active = null;
private static volatile long activeEnd = 0L;
private static final Queue<Notif> queue = new ArrayDeque<>();

public static DynamicIsland getInstance() {
return Instance.getDraggable(DynamicIsland.class);
}

public static void addNotification(String text, NotificationType type) {
Notif n = new Notif(text, type.color);
if (active == null || System.currentTimeMillis() >= activeEnd) {
active = n;
activeEnd = System.currentTimeMillis() + SHOW_MS;
} else {
queue.offer(n);
}
}

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

public static void strengthNotification() {
if (mc.player == null) return;
EquipmentSlot[] slots = {EquipmentSlot.HEAD, EquipmentSlot.CHEST,
EquipmentSlot.LEGS, EquipmentSlot.FEET};
String[] names = {"Шлем", "Нагрудник", "Поножи", "Ботинки"};
for (int i = 0; i < slots.length; i++) {
ItemStack s = mc.player.getEquippedStack(slots);
if (s.isEmpty() || !s.isDamageable()) continue;
float pct = (float)(s.getMaxDamage() - s.getDamage()) / s.getMaxDamage();
if (pct <= 0.1f && pct > 0f)
addNotification(names + " имеет низкую прочность!", NotificationType.WARNING);
}
}

private static final int BG = ColorUtil.getColor(18, 18, 22, 220);
private static final int BG_DARK = ColorUtil.getColor(12, 12, 16, 220);

private float pillW = 100f;
private static final float PILL_H = 22f;

private final float[] waveH = {4f, 8f, 5f, 9f};
private final float[] waveDir = {1f, -1f, 1f, -1f};
private final float[] waveSpd = {0.18f, 0.22f, 0.15f, 0.20f};

public DynamicIsland() {
super("Dynamic Island", 10, 10, 100, 22, false);
}

@override
public void tick() {
if (active != null && System.currentTimeMillis() >= activeEnd) {
Notif next = queue.poll();
active = next;
activeEnd = next != null ? System.currentTimeMillis() + SHOW_MS : 0L;
}

for (int i = 0; i < 4; i++) {
waveH += waveDir * waveSpd;
if (waveH >= 10f) {
waveH = 10f;
waveDir = -1f;
waveSpd = 0.12f + (float)(Math.random() * 0.18f);
}
if (waveH <= 3f) {
waveH = 3f;
waveDir = 1f;
waveSpd = 0.12f + (float)(Math.random() * 0.18f);
}
}
}

@override
public void drawDraggable(DrawContext context) {
if (mc.player == null || mc.world == null) return;

Hud hud = Hud.getInstance();
if (hud == null || !hud.interfaceSettings.isSelected("Dynamic Island")) {
return;
}

MatrixStack ms = context.getMatrices();
int sw = window.getScaledWidth();

boolean hasNotif = active != null && System.currentTimeMillis() < activeEnd;

// Media info - временно отключено, так как нет MediaUtils в проекте
boolean hasMedia = false;
String mediaTitle = "";

String time = LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm"));
FontRenderer fontTime = Fonts.getSize(12, Fonts.Type.BOLD);
FontRenderer fontName = Fonts.getSize(13, Fonts.Type.BOLD);
FontRenderer fontRegular = Fonts.getSize(11, Fonts.Type.DEFAULT);

float timeW = fontTime.getStringWidth(time);

float targetW;
if (hasNotif) {
float tw = fontRegular.getStringWidth(active.text());
targetW = 12f + 7f + 5f + tw + 12f;
} else if (hasMedia) {
String t = trimTitle(mediaTitle);
float tw = fontRegular.getStringWidth(t);
targetW = 12f + tw + 8f + waveGroupW() + 12f;
} else {
float nameW = fontName.getStringWidth(getDisplayName());
targetW = 12f + 12f + 4f + nameW + 12f; // 12f для кружочка + 4f отступ
}

pillW += (targetW - pillW) * 0.18f;

float pingGroupW = 4 * 3.8f + 3f;
float totalW = timeW + 8f + pillW + 8f + pingGroupW;
float startX = sw / 2f - totalW / 2f;
float pillX = startX + timeW + 8f;
float pillY = 5f;
float midY = pillY + PILL_H / 2f;
float textY = pillY + (PILL_H - fontName.getStringHeight(getDisplayName())) / 2f;
float timeY = pillY + (PILL_H - fontTime.getStringHeight(time)) / 2f;

// Время - отцентрировано по вертикали с островком
fontTime.drawString(ms, time, startX, timeY, ColorUtil.getText());

blurGlass.render(ShapeProperties.create(ms, pillX, pillY, pillW, PILL_H)
.round(PILL_H / 2f)
.color(BG)
.build());

rectangle.render(ShapeProperties.create(ms, pillX, pillY, pillW, PILL_H)
.round(PILL_H / 2f)
.thickness(0.15f)
.outlineColor(ColorUtil.getColor(255, 255, 255, 18))
.color(BG, BG_DARK, BG_DARK, BG)
.build());

float cx = pillX + 12f;

if (hasNotif) {
float dotR = 4f;
rectangle.render(ShapeProperties.create(ms, cx, midY - dotR, dotR * 2f, dotR * 2f)
.round(dotR)
.color(active.color())
.build());
cx += dotR * 2f + 6f;
fontRegular.drawString(ms, active.text(), cx, textY, ColorUtil.getText());
} else if (hasMedia) {
String t = trimTitle(mediaTitle);
fontRegular.drawString(ms, t, cx, textY, ColorUtil.getText());
cx += fontRegular.getStringWidth(t) + 8f;
renderWaveBars(ms, cx, midY);
} else {
renderCircle(ms, cx, midY - 5f, ColorUtil.getClientColor());
cx += 12f;
fontName.drawString(ms, getDisplayName(), cx, textY, ColorUtil.getClientColor());
}

float barsX = pillX + pillW + 8f;
float barsY = midY - 12f / 2f;
renderPing(ms, barsX, barsY);

setX((int) pillX);
setY((int) pillY);
setWidth((int) pillW);
setHeight((int) PILL_H);
}

private void renderWaveBars(MatrixStack ms, float x, float midY) {
int color = ColorUtil.getText(0.9f);
for (int i = 0; i < 4; i++) {
float bh = waveH;
rectangle.render(ShapeProperties.create(ms, x + i * 5f, midY - bh / 2f, 3f, bh)
.round(1.2f)
.color(color)
.build());
}
}

private float waveGroupW() {
return 4 * 3f + 3 * 2f;
}

private void renderPing(MatrixStack ms, float x, float y) {
int ping = getPlayerPing();
int lit = ping <= 50 ? 4 : ping <= 80 ? 3 : ping <= 120 ? 2 : ping <= 180 ? 1 : 0;
int[] maxH = {5, 7, 9, 12};
long t = System.currentTimeMillis();

for (int i = 0; i < 4; i++) {
float breath = (float)(Math.sin(t / 600.0 + i * 0.7) * 0.5 + 0.5);
float bh = i < lit ? maxH * (0.6f + 0.4f * breath) : maxH * (0.25f + 0.1f * breath);
int col = i < lit ? ColorUtil.getText(0.85f) : ColorUtil.getText(0.18f);

rectangle.render(ShapeProperties.create(ms, x + i * 3.8f, y + (12 - bh), 3.2f, bh)
.round(1.2f)
.color(col)
.build());
}
}

private void renderCircle(MatrixStack ms, float x, float y, int color) {
float radius = 5f;
rectangle.render(ShapeProperties.create(ms, x, y, radius * 2f, radius * 2f)
.round(radius)
.color(color)
.build());
}

private String trimTitle(String s) {
return s.length() > 22 ? s.substring(0, 20) + "…" : s;
}

private String getDisplayName() {
return "Pasta";
}

private int getPlayerPing() {
if (mc.player == null || mc.getNetworkHandler() == null) return 0;
PlayerListEntry e = mc.getNetworkHandler().getPlayerListEntry(mc.player.getUuid());
return e != null ? e.getLatency() : 0;
}
} такой островок сделала мне нейронка,выглядит убого, помогите исправить
1778309727614.png


ты что то можешь говорить про ужас нахуй? ты не можешь текста поправить блять тип,unlogin plsss
 
Чувак, я вайбкодер, я нихера не шарю в программировании, но если заливает человек сурсы, мб надо было исправить ошибки?
какие ошибки,ты че фрик нахуй,он просто берет сурс и сливает,ему нихуя фиксить и не надо,а если ты вайбкодер который не может найти блять буквально строчки с текстом по X-Y,то это смешно,ты понимаешь если ты не шаришь то нахуя ты что то либо делаешь,ты же даже той же базы джавы не знаешь и что да как там,и там еще написано СУКА LEAK,ты знаешь же что такое leak? если знаешь то бля не задавай такие вопросы типо "надо было исправить ошибки"
 
Чувак, я вайбкодер, я нихера не шарю в программировании, но если заливает человек сурсы, мб надо было исправить ошибки?
Я поэтому и написал что kiro делала, попросил помочь это поправить
 
какие ошибки,ты че фрик нахуй,он просто берет сурс и сливает,ему нихуя фиксить и не надо,а если ты вайбкодер который не может найти блять буквально строчки с текстом по X-Y,то это смешно,ты понимаешь если ты не шаришь то нахуя ты что то либо делаешь,ты же даже той же базы джавы не знаешь и что да как там,и там еще написано СУКА LEAK,ты знаешь же что такое leak? если знаешь то бля не задавай такие вопросы типо "надо было исправить ошибки"
Лан, я пожалуй ливну с форума
 
какие ошибки,ты че фрик нахуй,он просто берет сурс и сливает,ему нихуя фиксить и не надо,а если ты вайбкодер который не может найти блять буквально строчки с текстом по X-Y,то это смешно,ты понимаешь если ты не шаришь то нахуя ты что то либо делаешь,ты же даже той же базы джавы не знаешь и что да как там,и там еще написано СУКА LEAK,ты знаешь же что такое leak? если знаешь то бля не задавай такие вопросы типо "надо было исправить ошибки"
это настолько люди деградируют что циферки в коде поменять не могут
 
Назад
Сверху Снизу