Начинающий
- Статус
- Оффлайн
- Регистрация
- 12 Мар 2026
- Сообщения
- 106
- Реакции
- 0
- Выберите загрузчик игры
- Fabric
Пожалуйста, авторизуйтесь для просмотра ссылки.
Watermark:
package ARTheryx.screens.hud;
import ARTheryx.client.draggables.AbstractHudElement;
import ARTheryx.util.render.Render2D;
import ARTheryx.util.render.font.Fonts;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.network.PlayerListEntry;
import net.minecraft.util.math.Vec3d;
import java.awt.*;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
public class Watermark extends AbstractHudElement {
private String lastFps = "";
private String oldFps = "";
private long fpsAnimationStart = 0;
private String lastTime = "";
private String oldTime = "";
private long timeAnimationStart = 0;
private String lastPing = "";
private String oldPing = "";
private long pingAnimationStart = 0;
private String lastCoords = "";
private String oldCoords = "";
private long coordsAnimationStart = 0;
private String lastBps = "";
private String oldBps = "";
private long bpsAnimationStart = 0;
private static final long ANIMATION_DURATION = 200;
private static final float ANIMATION_OFFSET = 8.0f;
private static final int BLUR_RADIUS = 8;
private static final int CORNER_RADIUS = 7;
private static final String ICON_LOGO_ACCENT = "P";
private static final String ICON_FPS = "X";
private static final String ICON_CLOCK = "V";
private static final String ICON_COORDS_ACCENT = "W";
private static final String ICON_COMPASS = "G";
private static final String ICON_PING = "Q";
private static final String ICON_BPS = "T";
private static final float TEXT_SIZE = 7.5f;
private static final float ICON_SIZE = 8.0f;
private static final float BLOCK_HEIGHT = 20.0f;
private static final float BLOCK_GAP_X = 4.0f;
private static final float BLOCK_GAP_Y = 4.0f;
private static final float PADDING = 6.0f;
private static final float ICON_W = 10.0f;
private static final float SEP_GAP = 5.0f;
private static final float INNER_GAP = 4.0f;
private static final Color ORANGE = new Color(255, 123, 0);
private static final Color ORANGE_SOFT = new Color(255, 150, 50);
private static final Color TEXT_WHITE = new Color(235, 235, 235);
private static final Color TEXT_DIM = new Color(155, 155, 155);
private static final Color SEPARATOR = new Color(115, 115, 115, 255);
private static final Color BG1 = new Color(22, 22, 22);
private static final Color BG2 = new Color(16, 16, 16);
private static final int BG_A1 = 100;
private static final int BG_A2 = 45;
private static final int OUTLINE_A = 10;
private static final int LABEL_FADE_SPEED = 5;
private static final int LABEL_INDEX_STEP = 20;
private static final float LABEL_DARK_FACTOR = 0.10f;
public Watermark() {
super("Watermark", 10, 10, 200, 50, false);
startAnimation();
}
@Override
public void tick() {
}
private int clampAlpha(float a) {
return Math.max(0, Math.min(255, (int) (a * 255)));
}
private int withAlpha(Color c, int alpha) {
float f = alpha / 255.0f;
return new Color(c.getRed(), c.getGreen(), c.getBlue(), (int) (c.getAlpha() * f)).getRGB();
}
private int getPing() {
if (mc.player == null || mc.getNetworkHandler() == null) return 0;
PlayerListEntry entry = mc.getNetworkHandler().getPlayerListEntry(mc.player.getUuid());
return entry != null ? entry.getLatency() : 0;
}
@Override
public void drawDraggable(DrawContext context, int alpha) {
if (alpha <= 0) return;
float alphaFactor = alpha / 255.0f;
float x = getX();
float y = getY();
String releaseText = "Release";
String fpsNumber = String.valueOf(mc.getCurrentFps());
String fpsLabel = "Fps";
String time = LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"));
String coords = "0 0 0";
if (mc.player != null) {
coords = (int) mc.player.getX() + " " + (int) mc.player.getY() + " " + (int) mc.player.getZ();
}
String pingNumber = String.valueOf(getPing());
String pingLabel = "Ping";
double speed = 0.0;
if (mc.player != null) {
Vec3d vel = mc.player.getVelocity();
speed = Math.hypot(vel.x, vel.z) * 20.0;
}
String bpsNumber = String.format("%.1f", speed);
String bpsLabel = "b/s";
long now = System.currentTimeMillis();
if (!fpsNumber.equals(lastFps)) { oldFps = lastFps; lastFps = fpsNumber; fpsAnimationStart = now; }
if (!time.equals(lastTime)) { oldTime = lastTime; lastTime = time; timeAnimationStart = now; }
if (!pingNumber.equals(lastPing)) { oldPing = lastPing; lastPing = pingNumber; pingAnimationStart = now; }
if (!coords.equals(lastCoords)) { oldCoords = lastCoords; lastCoords = coords; coordsAnimationStart = now; }
if (!bpsNumber.equals(lastBps)) { oldBps = lastBps; lastBps = bpsNumber; bpsAnimationStart = now; }
float fpsAnim = Math.min(1.0f, (now - fpsAnimationStart) / (float) ANIMATION_DURATION);
float timeAnim = Math.min(1.0f, (now - timeAnimationStart) / (float) ANIMATION_DURATION);
float pingAnim = Math.min(1.0f, (now - pingAnimationStart) / (float) ANIMATION_DURATION);
float coordsAnim = Math.min(1.0f, (now - coordsAnimationStart) / (float) ANIMATION_DURATION);
float bpsAnim = Math.min(1.0f, (now - bpsAnimationStart) / (float) ANIMATION_DURATION);
float releaseW = Fonts.mntsb.getWidth(releaseText, TEXT_SIZE);
float fpsNumW = Fonts.mntsb.getWidth(fpsNumber, TEXT_SIZE);
float fpsLabelW = Fonts.mntsb.getWidth(fpsLabel, TEXT_SIZE);
float timeW = Fonts.mntsb.getWidth(time, TEXT_SIZE);
float coordsW = Fonts.mntsb.getWidth(coords, TEXT_SIZE);
float pingNumW = Fonts.mntsb.getWidth(pingNumber, TEXT_SIZE);
float pingLabelW = Fonts.mntsb.getWidth(pingLabel, TEXT_SIZE);
float bpsNumW = Fonts.mntsb.getWidth(bpsNumber, TEXT_SIZE);
float bpsLabelW = Fonts.mntsb.getWidth(bpsLabel, TEXT_SIZE);
float sepW = Fonts.mntsb.getWidth("|", TEXT_SIZE);
float bLogoAccent = PADDING + ICON_W + PADDING;
float bRelease = PADDING + releaseW + PADDING;
float bFps = PADDING + ICON_W + SEP_GAP + sepW + SEP_GAP + fpsNumW + INNER_GAP + fpsLabelW + PADDING;
float bTime = PADDING + ICON_W + SEP_GAP + sepW + SEP_GAP + timeW + PADDING;
float bAccent = PADDING + ICON_W + PADDING;
float bCoords = PADDING + ICON_W + SEP_GAP + sepW + SEP_GAP + coordsW + PADDING;
float bBps = PADDING + ICON_W + SEP_GAP + sepW + SEP_GAP + bpsNumW + INNER_GAP + bpsLabelW + PADDING;
float bPing = PADDING + ICON_W + SEP_GAP + sepW + SEP_GAP + pingNumW + INNER_GAP + pingLabelW + PADDING;
float topTotalW = bLogoAccent + BLOCK_GAP_X + bRelease + BLOCK_GAP_X + bFps + BLOCK_GAP_X + bTime;
float bottomTotalW = bAccent + BLOCK_GAP_X + bCoords + BLOCK_GAP_X + bBps + BLOCK_GAP_X + bPing;
float maxWidth = Math.max(topTotalW, bottomTotalW);
setWidth((int) Math.ceil(maxWidth));
setHeight((int) Math.ceil(BLOCK_HEIGHT * 2 + BLOCK_GAP_Y));
float ty = y + (BLOCK_HEIGHT - TEXT_SIZE) / 2.0f;
float iconY = y + (BLOCK_HEIGHT - ICON_SIZE) / 1.6f - 1.1f;
float cx = x;
float ix;
drawBlock(cx, y, bLogoAccent, BLOCK_HEIGHT, alphaFactor);
ix = cx + (bLogoAccent - ICON_W) / 2.0f;
Fonts.NEW_ICONS.draw(ICON_LOGO_ACCENT, ix, iconY - 0.5f, ICON_SIZE + 2, withAlpha(ORANGE, alpha));
cx += bLogoAccent + BLOCK_GAP_X;
drawBlock(cx, y, bRelease, BLOCK_HEIGHT, alphaFactor);
ix = cx + PADDING;
Fonts.mntsb.draw(releaseText, ix, ty, TEXT_SIZE, withAlpha(ORANGE_SOFT, alpha));
cx += bRelease + BLOCK_GAP_X;
drawBlock(cx, y, bFps, BLOCK_HEIGHT, alphaFactor);
ix = cx + PADDING;
Fonts.NEW_ICONS.draw(ICON_FPS, ix, iconY, ICON_SIZE + 2, withAlpha(TEXT_DIM, alpha));
ix += ICON_W + SEP_GAP;
Fonts.mntsb.draw("|", ix, ty, TEXT_SIZE, withAlpha(SEPARATOR, alpha));
ix += sepW + SEP_GAP;
drawAnimatedTextPerChar(fpsNumber, oldFps, ix, ty, TEXT_SIZE, fpsAnim, alpha);
ix += fpsNumW + INNER_GAP;
drawVodkaRemakeLabel(fpsLabel, ix, ty, TEXT_SIZE, alpha);
cx += bFps + BLOCK_GAP_X;
drawBlock(cx, y, bTime, BLOCK_HEIGHT, alphaFactor);
ix = cx + PADDING;
Fonts.NEW_ICONS.draw(ICON_CLOCK, ix, iconY, ICON_SIZE + 2, withAlpha(TEXT_DIM, alpha));
ix += ICON_W + SEP_GAP;
Fonts.mntsb.draw("|", ix, ty, TEXT_SIZE, withAlpha(SEPARATOR, alpha));
ix += sepW + SEP_GAP;
drawAnimatedTextPerChar(time, oldTime, ix, ty, TEXT_SIZE, timeAnim, alpha);
float by = y + BLOCK_HEIGHT + BLOCK_GAP_Y;
float bty = by + (BLOCK_HEIGHT - TEXT_SIZE) / 2.0f;
float bIconY = by + (BLOCK_HEIGHT - ICON_SIZE) / 1.6f - 1.0f;
cx = x;
drawBlock(cx, by, bAccent, BLOCK_HEIGHT, alphaFactor);
ix = cx + (bAccent - ICON_W) / 2.0f;
Fonts.NEW_ICONS.draw(ICON_COORDS_ACCENT, ix, bIconY - 0.5f, ICON_SIZE + 2, withAlpha(ORANGE, alpha));
cx += bAccent + BLOCK_GAP_X;
drawBlock(cx, by, bCoords, BLOCK_HEIGHT, alphaFactor);
ix = cx + PADDING;
Fonts.NEW_ICONS.draw(ICON_COMPASS, ix, bIconY, ICON_SIZE + 2, withAlpha(TEXT_DIM, alpha));
ix += ICON_W + SEP_GAP;
Fonts.mntsb.draw("|", ix, bty, TEXT_SIZE, withAlpha(SEPARATOR, alpha));
ix += sepW + SEP_GAP;
drawAnimatedTextPerChar(coords, oldCoords, ix, bty, TEXT_SIZE, coordsAnim, alpha);
cx += bCoords + BLOCK_GAP_X;
drawBlock(cx, by, bBps, BLOCK_HEIGHT, alphaFactor);
ix = cx + PADDING;
Fonts.NEW_ICONS.draw(ICON_BPS, ix, bIconY, ICON_SIZE + 2, withAlpha(TEXT_DIM, alpha));
ix += ICON_W + SEP_GAP;
Fonts.mntsb.draw("|", ix, bty, TEXT_SIZE, withAlpha(SEPARATOR, alpha));
ix += sepW + SEP_GAP;
drawAnimatedTextPerChar(bpsNumber, oldBps, ix, bty, TEXT_SIZE, bpsAnim, alpha);
ix += bpsNumW + INNER_GAP;
drawVodkaRemakeLabel(bpsLabel, ix, bty, TEXT_SIZE, alpha);
cx += bBps + BLOCK_GAP_X;
drawBlock(cx, by, bPing, BLOCK_HEIGHT, alphaFactor);
ix = cx + PADDING;
Fonts.NEW_ICONS.draw(ICON_PING, ix, bIconY, ICON_SIZE + 2, withAlpha(TEXT_DIM, alpha));
ix += ICON_W + SEP_GAP;
Fonts.mntsb.draw("|", ix, bty, TEXT_SIZE, withAlpha(SEPARATOR, alpha));
ix += sepW + SEP_GAP;
drawAnimatedTextPerChar(pingNumber, oldPing, ix, bty, TEXT_SIZE, pingAnim, alpha);
ix += pingNumW + INNER_GAP;
drawVodkaRemakeLabel(pingLabel, ix, bty, TEXT_SIZE, alpha);
}
private void drawBlock(float x, float y, float w, float h, float alphaFactor) {
Render2D.blur(x, y, w, h, BLUR_RADIUS, CORNER_RADIUS);
Render2D.gradientRect(
x, y, w, h,
new int[]{
new Color(BG1.getRed(), BG1.getGreen(), BG1.getBlue(), (int) (BG_A1 * alphaFactor)).getRGB(),
new Color(BG2.getRed(), BG2.getGreen(), BG2.getBlue(), (int) (BG_A2 * alphaFactor)).getRGB(),
new Color(BG1.getRed(), BG1.getGreen(), BG1.getBlue(), (int) (BG_A1 * alphaFactor)).getRGB(),
new Color(BG2.getRed(), BG2.getGreen(), BG2.getBlue(), (int) (BG_A2 * alphaFactor)).getRGB()
},
CORNER_RADIUS
);
Render2D.outline(
x, y, w, h, 0.35f,
new Color(95, 95, 95, (int) (OUTLINE_A * alphaFactor)).getRGB(),
CORNER_RADIUS
);
}
private void drawAnimatedTextPerChar(String newText, String oldText, float x, float y, float size, float progress, int alpha) {
int baseColor = withAlpha(TEXT_WHITE, alpha);
if (oldText.isEmpty() || progress >= 1.0f) {
Fonts.mntsb.draw(newText, x, y, size, baseColor);
return;
}
float offsetX = x;
int maxLen = Math.max(newText.length(), oldText.length());
String paddedNew = padLeft(newText, maxLen);
String paddedOld = padLeft(oldText, maxLen);
for (int i = 0; i < paddedNew.length(); i++) {
char newChar = paddedNew.charAt(i);
char oldChar = paddedOld.charAt(i);
if (newChar == ' ' && oldChar == ' ') {
offsetX += Fonts.mntsb.getWidth(" ", size);
continue;
}
float charWidth = Fonts.mntsb.getWidth(String.valueOf(newChar != ' ' ? newChar : oldChar), size);
boolean isNewDigit = Character.isDigit(newChar) || newChar == '.' || newChar == ':' || newChar == '-';
boolean isOldDigit = Character.isDigit(oldChar) || oldChar == '.' || oldChar == ':' || oldChar == '-';
boolean hasChanged = newChar != oldChar;
if (!hasChanged || (!isNewDigit && !isOldDigit)) {
if (newChar != ' ') {
Fonts.mntsb.draw(String.valueOf(newChar), offsetX, y, size, baseColor);
}
} else {
float eased = easeOutCubic(progress);
if (oldChar != ' ' && isOldDigit) {
float oldA = 1.0f - eased;
float oldY = eased * ANIMATION_OFFSET;
int oldAlphaC = clampAlpha(oldA * (alpha / 255.0f));
if (oldAlphaC > 0) {
int oldColor = new Color(TEXT_WHITE.getRed(), TEXT_WHITE.getGreen(), TEXT_WHITE.getBlue(), oldAlphaC).getRGB();
Fonts.mntsb.draw(String.valueOf(oldChar), offsetX, y + oldY, size, oldColor);
}
}
if (newChar != ' ' && isNewDigit) {
float newA = eased;
float newY = (1.0f - eased) * -ANIMATION_OFFSET;
int newAlphaC = clampAlpha(newA * (alpha / 255.0f));
if (newAlphaC > 0) {
int newColor = new Color(TEXT_WHITE.getRed(), TEXT_WHITE.getGreen(), TEXT_WHITE.getBlue(), newAlphaC).getRGB();
Fonts.mntsb.draw(String.valueOf(newChar), offsetX, y + newY, size, newColor);
}
}
}
offsetX += charWidth;
}
}
private String padLeft(String text, int length) {
if (text.length() >= length) return text;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length - text.length(); i++) sb.append(' ');
sb.append(text);
return sb.toString();
}
private float easeOutCubic(float t) {
return 1.0f - (float) Math.pow(1.0 - t, 3);
}
private int overCol(int c1, int c2, float t) {
t = Math.max(0f, Math.min(1f, t));
int a1 = (c1 >>> 24) & 0xFF;
int r1 = (c1 >>> 16) & 0xFF;
int g1 = (c1 >>> 8) & 0xFF;
int b1 = (c1) & 0xFF;
int a2 = (c2 >>> 24) & 0xFF;
int r2 = (c2 >>> 16) & 0xFF;
int g2 = (c2 >>> 8) & 0xFF;
int b2 = (c2) & 0xFF;
int a = (int) (a1 + (a2 - a1) * t);
int r = (int) (r1 + (r2 - r1) * t);
int g = (int) (g1 + (g2 - g1) * t);
int b = (int) (b1 + (b2 - b1) * t);
return (a << 24) | (r << 16) | (g << 8) | b;
}
private int multDark(int color, float percent01) {
int a = (color >>> 24) & 0xFF;
int r = (color >>> 16) & 0xFF;
int g = (color >>> 8) & 0xFF;
int b = (color) & 0xFF;
r = Math.max(0, Math.min(255, Math.round(r * percent01)));
g = Math.max(0, Math.min(255, Math.round(g * percent01)));
b = Math.max(0, Math.min(255, Math.round(b * percent01)));
return (a << 24) | (r << 16) | (g << 8) | b;
}
private int fade(int speed, int index, int first, int second) {
int angle = (int) ((System.currentTimeMillis() / speed + index) % 360);
angle = angle >= 180 ? 360 - angle : angle;
return overCol(first, second, angle / 180f);
}
private void drawVodkaRemakeLabel(String text, float x, float y, float size, int alpha) {
int first = TEXT_DIM.getRGB();
int second = multDark(first, LABEL_DARK_FACTOR);
float ox = x;
int len = text.length();
for (int i = 0; i < len; i++) {
String s = String.valueOf(text.charAt(i));
int idx = (len - 1 - i) * LABEL_INDEX_STEP;
int c = fade(LABEL_FADE_SPEED, idx, first, second);
int a = (int) (((c >>> 24) & 0xFF) * (alpha / 255f));
c = (c & 0x00FFFFFF) | (a << 24);
Fonts.mntsb.draw(s, ox, y, size, c);
ox += Fonts.mntsb.getWidth(s, size);
}
}
}
Последнее редактирование: