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

Визуальная часть LineGlyps Rich 1.21.4

Начинающий
Начинающий
Статус
Оффлайн
Регистрация
30 Окт 2025
Сообщения
14
Реакции
0
Выберите загрузчик игры
  1. Fabric
Иишка, надо допилить(лень убирать подписи от ии)
Java:
Expand Collapse Copy
package fun.rich.features.impl.render;

import fun.rich.features.module.Module;
import fun.rich.features.module.ModuleCategory;
import fun.rich.features.module.setting.implement.BooleanSetting;
import fun.rich.features.module.setting.implement.ColorSetting;
import fun.rich.features.module.setting.implement.SelectSetting;
import fun.rich.features.module.setting.implement.SliderSettings;
import fun.rich.utils.client.managers.event.EventHandler;
import fun.rich.events.render.WorldRenderEvent;
import fun.rich.utils.display.color.ColorAssist;
import fun.rich.utils.display.geometry.Render3D;
import fun.rich.utils.client.Instance;
import net.minecraft.client.render.Camera;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.Vec3d;
import lombok.AccessLevel;
import lombok.experimental.FieldDefaults;
import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.gl.ShaderProgramKeys;
import net.minecraft.client.render.*;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.RotationAxis;
import org.joml.Matrix4f;
import org.joml.Vector4i;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Iterator;

@FieldDefaults(level = AccessLevel.PRIVATE)
public class LineGlyphs extends Module {

    public static LineGlyphs getInstance() {
        return Instance.get(LineGlyphs.class);
    }

    BooleanSetting glowing = new BooleanSetting("Свечение", "Добавляет свечение линиям").setValue(true);
    BooleanSetting dashed = new BooleanSetting("Пунктир", "Делает линии пунктирными").setValue(false);
    SelectSetting colorMode = new SelectSetting("Режим цвета", "Выбор режима цвета").value("Client", "Picker", "DoublePicker").selected("Client");
    ColorSetting pickColor1 = new ColorSetting("Цвет 1", "Первый цвет").value(ColorAssist.getColor(100, 200, 255)).visible(() -> colorMode.getSelected().contains("Picker"));
    ColorSetting pickColor2 = new ColorSetting("Цвет 2", "Второй цвет").value(ColorAssist.getColor(255, 100, 200)).visible(() -> colorMode.getSelected().equals("DoublePicker"));

    final List<FallingLine> lines = new ArrayList<>();
    final Random random = new Random();
    
    // Константы (бывшие настройки)
    private static final int LINE_COUNT = 120; // Увеличено с 85 до 120
    private static final float FALL_SPEED = 0.07f;
    private static final float LINE_LENGTH = 17f;
    private static final float SEGMENT_LENGTH = 2f;
    private static final float ZIGZAG_WIDTH = 5f;

    public LineGlyphs() {
        super("LineGlyphs", "Line Glyphs", ModuleCategory.RENDER);
        setup(glowing, dashed, colorMode, pickColor1, pickColor2);
    }

    @Override
    public void activate() {
        super.activate();
        generateLines();
    }

    @Override
    public void deactivate() {
        super.deactivate();
        lines.clear();
    }

    private void generateLines() {
        lines.clear();
        if (mc.player == null) return;
        
        for (int i = 0; i < LINE_COUNT; i++) {
            lines.add(new FallingLine(random, mc.player.getPos()));
        }
    }

    @EventHandler
    public void onWorldRender(WorldRenderEvent e) {
        if (mc.player == null) return;

        // Подсчитываем сколько линий нужно заспавнить
        int linesToSpawn = LINE_COUNT - lines.size();
        
        // Обновляем линии и удаляем те, что нужно респавнить
        Iterator<FallingLine> iterator = lines.iterator();
        while (iterator.hasNext()) {
            FallingLine line = iterator.next();
            line.update(mc.player.getPos(), FALL_SPEED, SEGMENT_LENGTH, ZIGZAG_WIDTH, LINE_LENGTH);
            
            // Если линия должна респавниться - удаляем и увеличиваем счетчик
            if (line.shouldRespawn(mc.player.getPos())) {
                iterator.remove();
                linesToSpawn++;
            }
        }
        
        // Спавним все нужные линии сразу (мгновенно)
        for (int i = 0; i < linesToSpawn; i++) {
            lines.add(new FallingLine(random, mc.player.getPos()));
        }

        // Рендерим линии
        renderLines(e.getStack());
    }

    private void renderLines(MatrixStack stack) {
        if (lines.isEmpty() || mc.gameRenderer == null) return;
        
        Camera camera = mc.gameRenderer.getCamera();
        Vec3d camPos = camera.getPos();
        
        // Рендерим каждую линию
        for (int lineIndex = 0; lineIndex < lines.size(); lineIndex++) {
            FallingLine line = lines.get(lineIndex);
            if (line.points.size() < 2) continue;
            
            int color = getColor(lineIndex);
            
            // Рисуем линию между всеми точками
            for (int i = 0; i < line.points.size() - 1; i++) {
                Vec3d start = line.points.get(i);
                Vec3d end = line.points.get(i + 1);
                
                // Проверяем, не слишком ли далеко от камеры
                if (start.distanceTo(camPos) > 60 || end.distanceTo(camPos) > 60) continue;
                
                // Вычисляем альфу для каждого сегмента (затухание к началу следа)
                float segmentAlpha = (float)(i + 1) / line.points.size();
                int segmentColor = ColorAssist.setAlpha(color, (int)(segmentAlpha * 255));
                
                // Рисуем линию с эффектом свечения если включено
                float width = glowing.isValue() ? 2.5f : 1.5f;
                
                // Если включен пунктир - рисуем сегментами
                if (dashed.isValue()) {
                    drawDashedLine(start, end, segmentColor, width);
                    if (glowing.isValue()) {
                        int glowColor = ColorAssist.setAlpha(color, (int)(segmentAlpha * 100));
                        drawDashedLine(start, end, glowColor, 4.0f);
                    }
                } else {
                    // Используем Render3D для рендеринга сплошных линий
                    Render3D.drawLine(start, end, segmentColor, width, true);
                    
                    // Если включено свечение - рисуем дополнительную толстую линию с меньшей прозрачностью
                    if (glowing.isValue()) {
                        int glowColor = ColorAssist.setAlpha(color, (int)(segmentAlpha * 100));
                        Render3D.drawLine(start, end, glowColor, 4.0f, true);
                    }
                }
            }
            
            // Рисуем кружки в точках поворота
            renderTurnCircles(stack, line, color, camPos);
        }
    }
    
    private void drawDashedLine(Vec3d start, Vec3d end, int color, float width) {
        // Параметры пунктира
        double dashLength = 0.15; // Длина штриха
        double gapLength = 0.1;   // Длина пробела
        double totalPattern = dashLength + gapLength;
        
        // Вычисляем направление и длину линии
        Vec3d direction = end.subtract(start);
        double lineLength = direction.length();
        Vec3d normalizedDir = direction.normalize();
        
        // Рисуем штрихи
        double currentDistance = 0;
        while (currentDistance < lineLength) {
            double dashEnd = Math.min(currentDistance + dashLength, lineLength);
            
            Vec3d dashStart = start.add(normalizedDir.multiply(currentDistance));
            Vec3d dashEndPos = start.add(normalizedDir.multiply(dashEnd));
            
            Render3D.drawLine(dashStart, dashEndPos, color, width, true);
            
            currentDistance += totalPattern;
        }
    }
    
    private void renderTurnCircles(MatrixStack stack, FallingLine line, int color, Vec3d camPos) {
        if (line.turnPoints.isEmpty() || mc.gameRenderer == null) return;
        
        Camera camera = mc.gameRenderer.getCamera();
        float pitch = camera.getPitch();
        float yaw = camera.getYaw();
        
        // Рисуем bloom частицу в каждой точке поворота (как в WorldParticles)
        for (Vec3d turnPoint : line.turnPoints) {
            // Проверяем расстояние от камеры
            if (turnPoint.distanceTo(camPos) > 60) continue;
            
            // Вычисляем альфу для частицы (затухание для старых точек)
            float alpha = 1.0f;
            if (!line.points.isEmpty()) {
                Vec3d lastPoint = line.points.get(line.points.size() - 1);
                double distanceFromEnd = turnPoint.distanceTo(lastPoint);
                alpha = Math.max(0.3f, 1.0f - (float)(distanceFromEnd / LINE_LENGTH));
            }
            
            int particleColor = ColorAssist.setAlpha(color, (int)(alpha * 255));
            float size = 0.2f;
            
            // Позиция относительно камеры
            double posX = turnPoint.x - camPos.x;
            double posY = turnPoint.y - camPos.y;
            double posZ = turnPoint.z - camPos.z;
            
            // Создаем матрицу для частицы (как в WorldParticles)
            MatrixStack matrices = new MatrixStack();
            matrices.push();
            matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(pitch));
            matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(yaw + 180.0F));
            matrices.translate(posX, posY, posZ);
            matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(-yaw));
            matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(pitch));
            
            // Используем Render3D.drawTexture как в WorldParticles
            Render3D.drawTexture(
                matrices.peek(),
                Identifier.of("textures/features/particles/bloom.png"),
                -size / 2,
                -size / 2,
                size,
                size,
                new org.joml.Vector4i(particleColor, particleColor, particleColor, particleColor),
                true // depth = true
            );
            
            matrices.pop();
        }
    }

    private int getColor(int index) {
        return switch (colorMode.getSelected()) {
            case "Client" -> ColorAssist.getClientColor();
            case "Picker" -> pickColor1.getColor();
            case "DoublePicker" -> ColorAssist.gradient(pickColor1.getColor(), pickColor2.getColor(), index, 10);
            default -> ColorAssist.getClientColor();
        };
    }

    // Внутренний класс для представления падающей линии
    private static class FallingLine {
        List<Vec3d> points = new ArrayList<>();
        List<Vec3d> turnPoints = new ArrayList<>(); // Точки поворота для кружков
        Vec3d currentDirection; // Текущее направление движения
        double distanceTraveled = 0; // Пройденное расстояние в текущем сегменте
        double currentSegmentLength; // Длина текущего сегмента
        Random random = new Random();

        public FallingLine(Random random, Vec3d playerPos) {
            // Спавним линию прямо перед игроком на высоте 14 блоков
            if (mc.gameRenderer == null || mc.player == null) {
                // Fallback если камера недоступна
                double range = 15;
                double x = playerPos.x + (random.nextDouble() - 0.5) * range;
                double y = playerPos.y + random.nextDouble() * 14; // От пола до 14 блоков вверх
                double z = playerPos.z + (random.nextDouble() - 0.5) * range;
                points.add(new Vec3d(x, y, z));
            } else {
                // Получаем направление взгляда игрока
                float yaw = mc.player.getYaw();
                float pitch = mc.player.getPitch();
                double yawRad = Math.toRadians(yaw);
                double pitchRad = Math.toRadians(pitch);
                
                // Спавним на расстоянии 2-8 блоков
                double distance = 2 + random.nextDouble() * 6;
                
                // Направление взгляда (с учетом pitch)
                double dirX = -Math.sin(yawRad) * Math.cos(pitchRad);
                double dirY = -Math.sin(pitchRad);
                double dirZ = Math.cos(yawRad) * Math.cos(pitchRad);
                
                // Вычисляем вектора "вправо" и "вверх" относительно направления взгляда
                // Вектор вправо = cross(направление, мировой_вверх)
                Vec3d lookDir = new Vec3d(dirX, dirY, dirZ);
                Vec3d worldUp = new Vec3d(0, 1, 0);
                Vec3d right = lookDir.crossProduct(worldUp).normalize();
                // Вектор вверх = cross(вправо, направление)
                Vec3d up = right.crossProduct(lookDir).normalize();
                
                // Добавляем смещение равномерно по всему экрану
                // Используем равномерное распределение для покрытия всего экрана
                double horizontalSpread = (random.nextDouble() - 0.5) * 24; // -12 до +12 блоков (увеличено)
                double verticalSpread = (random.nextDouble() - 0.5) * 18; // -9 до +9 блоков (увеличено)
                
                // Базовая позиция перед игроком
                double x = playerPos.x + dirX * distance;
                double y = playerPos.y + dirY * distance;
                double z = playerPos.z + dirZ * distance;
                
                // Добавляем смещение по краям экрана
                x += right.x * horizontalSpread + up.x * verticalSpread;
                y += right.y * horizontalSpread + up.y * verticalSpread;
                z += right.z * horizontalSpread + up.z * verticalSpread;
                
                points.add(new Vec3d(x, y, z));
            }
            
            // Начинаем со случайного направления
            currentDirection = getRandomDirection();
            
            // Случайная длина первого сегмента
            currentSegmentLength = 0.5 + random.nextDouble() * 1.5; // 0.5-2.0 блоков
        }

        public void update(Vec3d playerPos, float fallSpeed, float segmentLengthSetting, float zigzagWidth, float maxLineLength) {
            if (points.isEmpty()) return;
            
            Vec3d lastPoint = points.get(points.size() - 1);
            
            // Двигаемся в текущем направлении
            Vec3d movement = currentDirection.multiply(fallSpeed);
            Vec3d newPoint = lastPoint.add(movement);
            
            points.add(newPoint);
            distanceTraveled += fallSpeed;
            
            // Проверяем нужно ли повернуть (прошли весь сегмент)
            if (distanceTraveled >= currentSegmentLength) {
                // Сохраняем точку поворота для кружка
                turnPoints.add(newPoint);
                
                // Делаем поворот!
                makeRandomTurn(zigzagWidth);
                distanceTraveled = 0;
                // Новая случайная длина сегмента (0.5-2.0 блоков, полностью случайная)
                currentSegmentLength = 0.5 + random.nextDouble() * 1.5;
            }
            
            // Удаляем старые точки если линия стала длиннее максимальной длины
            double totalLength = calculateTotalLength();
            while (totalLength > maxLineLength && points.size() > 2) {
                Vec3d removedPoint = points.remove(0);
                // Удаляем turnPoints которые были удалены вместе с точками линии
                turnPoints.removeIf(turnPoint -> turnPoint.equals(removedPoint));
                totalLength = calculateTotalLength();
            }
            
            // Дополнительно удаляем turnPoints которые слишком далеко от текущей линии
            if (!points.isEmpty()) {
                Vec3d firstPoint = points.get(0);
                turnPoints.removeIf(turnPoint -> {
                    // Проверяем есть ли эта точка в текущем списке points
                    boolean isInPoints = points.stream().anyMatch(p -> p.distanceTo(turnPoint) < 0.1);
                    // Если точки нет в списке и она далеко от начала - удаляем
                    return !isInPoints && turnPoint.distanceTo(firstPoint) > maxLineLength;
                });
            }
        }
        
        private double calculateTotalLength() {
            double length = 0;
            for (int i = 0; i < points.size() - 1; i++) {
                length += points.get(i).distanceTo(points.get(i + 1));
            }
            return length;
        }
        
        private void makeRandomTurn(float zigzagWidth) {
            // Выбираем полностью случайное направление (6 основных направлений)
            currentDirection = getRandomDirection();
        }
        
        private Vec3d getRandomDirection() {
            int directionType = random.nextInt(6);
            
            return switch (directionType) {
                case 0 -> new Vec3d(1, 0, 0); // Вправо
                case 1 -> new Vec3d(-1, 0, 0); // Влево
                case 2 -> new Vec3d(0, 1, 0); // Вверх
                case 3 -> new Vec3d(0, -1, 0); // Вниз
                case 4 -> new Vec3d(0, 0, 1); // Вперед
                case 5 -> new Vec3d(0, 0, -1); // Назад
                default -> new Vec3d(0, -1, 0);
            };
        }
        
        public boolean shouldRespawn(Vec3d playerPos) {
            if (points.isEmpty()) return true;
            
            Vec3d lastPoint = points.get(points.size() - 1);
            
            // Респавним если линия ушла слишком далеко от игрока (уменьшено до 18)
            double distance = lastPoint.distanceTo(playerPos);
            if (distance > 18) return true;
            
            // Респавним если линия вне поля зрения камеры (более агрессивно)
            if (mc.gameRenderer != null) {
                Camera camera = mc.gameRenderer.getCamera();
                Vec3d cameraPos = camera.getPos();
                Vec3d cameraDir = Vec3d.fromPolar(camera.getPitch(), camera.getYaw());
                
                // Вектор от камеры к линии
                Vec3d toLine = lastPoint.subtract(cameraPos).normalize();
                
                // Вычисляем угол между направлением камеры и направлением к линии
                double dotProduct = cameraDir.dotProduct(toLine);
                
                // Если угол больше 60 градусов (линия сбоку или позади), респавним быстрее
                // Было -0.3 (107 градусов), стало 0.5 (60 градусов) - более агрессивный респавн
                if (dotProduct < 0.5) return true;
            }
            
            return false;
        }
    }
}
 

Вложения

  • Minecraft Screenshot 2026.03.15 - 12.40.00.75.png
    Minecraft Screenshot 2026.03.15 - 12.40.00.75.png
    1.7 MB · Просмотры: 247
Назад
Сверху Снизу