- Выберите загрузчик игры
- Fabric
Салют югейм, сливаю вам Targed ESP на Zenith recode, чо то делал через клауд опус, чё-то сам.
Не бейте ногами пж первая тема.
SS: Прикреплён снизу
Не бейте ногами пж первая тема.
SS: Прикреплён снизу
есп:
package zenith.zov.client.modules.impl.render;
import com.darkmagician6.eventapi.EventTarget;
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.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity;
import net.minecraft.util.hit.HitResult;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.*;
import org.joml.Matrix4f;
import zenith.zov.base.events.impl.render.EventRender3D;
import zenith.zov.client.modules.api.Category;
import zenith.zov.client.modules.api.Module;
import zenith.zov.client.modules.api.ModuleAnnotation;
import zenith.zov.client.modules.api.setting.impl.BooleanSetting;
import zenith.zov.client.modules.api.setting.impl.ColorSetting;
import zenith.zov.client.modules.api.setting.impl.ModeSetting;
import zenith.zov.client.modules.api.setting.impl.NumberSetting;
import zenith.zov.client.modules.impl.combat.Aura;
import zenith.zov.Zenith;
import zenith.zov.utility.render.display.base.color.ColorRGBA;
import java.awt.*;
import static zenith.zov.utility.math.MathUtil.interpolate;
@ModuleAnnotation(name = "TargetESP", category = Category.RENDER, description = "Подсвечивает цель ауры")
public final class TargetESP extends Module {
public static final TargetESP INSTANCE = new TargetESP();
// Режим
public final ModeSetting mode = new ModeSetting("Режим", "Души", "Кружок", "Призраки", "Кристаллы");
public final BooleanSetting aimEsp = new BooleanSetting("При наведении", false);
// Настройки для Душ
private final ModeSetting soulsMovement = new ModeSetting("Движение душ", () -> mode.is("Души"), "Стандарт", "Волна", "Спираль", "Пульс", "Сквозь");
private final NumberSetting soulsSpeed = new NumberSetting("Скорость", 0.62f, 0.1f, 2.0f, 0.05f, () -> mode.is("Души"));
private final NumberSetting soulsSize = new NumberSetting("Размер", 0.6f, 0.2f, 1.5f, 0.05f, () -> mode.is("Души"));
private final NumberSetting soulsDistance = new NumberSetting("Дистанция", 1.04f, 0.5f, 2.0f, 0.05f, () -> mode.is("Души"));
private final NumberSetting soulsCount = new NumberSetting("Количество", 4, 2, 8, 1, () -> mode.is("Души"));
private final NumberSetting soulsLength = new NumberSetting("Длина хвоста", 10, 5, 20, 1, () -> mode.is("Души"));
private final NumberSetting soulsVerticalSpeed = new NumberSetting("Вертикальная скорость", 1.0f, 0.1f, 3.0f, 0.1f,
() -> mode.is("Души") && !soulsMovement.is("Сквозь") && !soulsMovement.is("Стандарт"));
private final NumberSetting soulsVerticalRange = new NumberSetting("Вертикальный диапазон", 0.5f, 0.1f, 1.5f, 0.1f,
() -> mode.is("Души") && !soulsMovement.is("Сквозь") && !soulsMovement.is("Стандарт"));
// Настройки для Призраков (упрощённые - без разных движений)
private final NumberSetting ghostSpeed = new NumberSetting("Скорость призраков", 0.62f, 0.1f, 2.0f, 0.05f, () -> mode.is("Призраки"));
private final NumberSetting ghostRadius = new NumberSetting("Радиус призраков", 1.04f, 0.5f, 2.0f, 0.05f, () -> mode.is("Призраки"));
private final NumberSetting ghostSize = new NumberSetting("Размер призраков", 0.6f, 0.2f, 1.5f, 0.05f, () -> mode.is("Призраки"));
private final NumberSetting ghostTrailLength = new NumberSetting("Длина хвоста призраков", 10, 5, 20, 1, () -> mode.is("Призраки"));
private final NumberSetting ghostCount = new NumberSetting("Количество призраков", 3, 1, 6, 1, () -> mode.is("Призраки"));
// Настройки для Кристаллов
private final NumberSetting crystalSpeed = new NumberSetting("Скорость вращения", 0.5f, 0.1f, 2.0f, 0.1f, () -> mode.is("Кристаллы"));
private final NumberSetting crystalSize = new NumberSetting("Размер кристаллов", 0.05f, 0.02f, 0.15f, 0.01f, () -> mode.is("Кристаллы"));
// Цвета
private final BooleanSetting useThemeColor = new BooleanSetting("Цвет из темы", true);
private final ColorSetting mainColor = new ColorSetting("Основной цвет", new ColorRGBA(255, 100, 100, 255), () -> !useThemeColor.isEnabled());
private final BooleanSetting hitColorEnabled = new BooleanSetting("Цвет при ударе", true, () -> !useThemeColor.isEnabled());
private final ColorSetting hitColor = new ColorSetting("Цвет удара", new ColorRGBA(255, 0, 0, 255), () -> !useThemeColor.isEnabled() && hitColorEnabled.isEnabled());
private final Identifier bloomTexture = Identifier.of("zenith", "textures/particles/bloom.png");
private final Identifier sparkTexture = Identifier.of("zenith", "textures/particles/spark.png");
private LivingEntity target;
private LivingEntity lastTarget;
private double scale = 0.0D;
// Кэшированные объекты
private final MatrixStack reusableMatrices = new MatrixStack();
// Кристаллы
private LivingEntity lastCrystalTarget = null;
private final java.util.List<CrystalData> crystalList = new java.util.ArrayList<>();
private float crystalRotationAngle = 0;
private TargetESP() {
}
@EventTarget
public void onRender3D(EventRender3D event) {
if (!this.isEnabled()) return;
updateTarget();
LivingEntity currentTarget = target != null ? target : lastTarget;
if (currentTarget == null) return;
if (target != null) {
scale = Math.min(scale + 0.1, 1.0);
} else {
scale = Math.max(scale - 0.1, 0.0);
}
if (scale <= 0) return;
float hitProgress = getHitProgress(currentTarget);
float anim = (float) scale;
switch (mode.get()) {
case "Души" -> renderSouls(currentTarget, anim, hitProgress);
case "Кружок" -> renderCircle(currentTarget, event.getMatrix(), event.getPartialTicks(), hitProgress);
case "Призраки" -> renderGhosts(currentTarget, anim, hitProgress);
case "Кристаллы" -> renderCrystals(currentTarget, event.getMatrix(), anim, hitProgress);
}
}
private void updateTarget() {
LivingEntity newTarget = Aura.INSTANCE.getTarget();
if (aimEsp.isEnabled() && mc.crosshairTarget != null &&
mc.crosshairTarget.getType() == HitResult.Type.ENTITY &&
mc.crosshairTarget instanceof net.minecraft.util.hit.EntityHitResult entityHit &&
entityHit.getEntity() instanceof LivingEntity living) {
if (living.isAlive() && living != mc.player) {
newTarget = living;
}
}
this.target = newTarget;
if (this.target != null) {
this.lastTarget = this.target;
}
}
private float getHitProgress(LivingEntity target) {
return target.hurtTime > 0 ? Math.min(target.hurtTime / 10f, 1f) : 0f;
}
private int getColor(float hitProgress) {
int base;
if (useThemeColor.isEnabled()) {
base = Zenith.getInstance().getThemeManager().getClientColor(0).getRGB();
} else {
base = mainColor.getColor().getRGB();
}
if (!useThemeColor.isEnabled() && hitColorEnabled.isEnabled() && hitProgress > 0) {
return blendColors(base, hitColor.getColor().getRGB(), hitProgress);
}
return base;
}
private int getColorStyle(int hue) {
return Color.getHSBColor(hue / 360f, 1.0f, 1.0f).getRGB();
}
// ============ SOULS (Души) ============
private void renderSouls(LivingEntity target, float anim, float hitProgress) {
Camera camera = mc.getEntityRenderDispatcher().camera;
if (camera == null) return;
String movement = soulsMovement.get();
// Режим "Сквозь" - души летают через игрока
if (movement.equals("Сквозь")) {
renderSoulsThrough(target, anim, hitProgress);
return;
}
float delta = mc.getRenderTickCounter().getTickDelta(true);
Vec3d camPos = camera.getPos();
double tX = interpolate(target.prevX, target.getX(), delta) - camPos.x;
double tY = interpolate(target.prevY, target.getY(), delta) - camPos.y;
double tZ = interpolate(target.prevZ, target.getZ(), delta) - camPos.z;
boolean canSee = mc.player.canSee(target);
double iAge = interpolate(mc.player.age - 1, mc.player.age, delta);
float halfHeight = target.getHeight() / 2 + 0.2F;
float baseWidth = target.getWidth() + 0.2f;
float minY = 0.2f;
float maxY = target.getHeight() - 0.2F;
float hitEffect = Math.min(hitProgress * 2f, 2f);
float acceleration = (float) Math.sin(hitEffect * Math.PI) * 0.18f;
float bany = (float) Math.sin(hitEffect * Math.PI) * -0.04f;
float speed = soulsSpeed.getCurrent();
float size = soulsSize.getCurrent();
float distance = soulsDistance.getCurrent();
int count = (int) soulsCount.getCurrent();
int length = (int) soulsLength.getCurrent();
float vertSpeed = soulsVerticalSpeed.getCurrent();
float vertRange = soulsVerticalRange.getCurrent();
RenderSystem.enableBlend();
RenderSystem.blendFunc(GlStateManager.SrcFactor.SRC_ALPHA, GlStateManager.DstFactor.ONE);
RenderSystem.setShaderTexture(0, bloomTexture);
RenderSystem.setShader(ShaderProgramKeys.POSITION_TEX_COLOR);
if (canSee) {
RenderSystem.enableDepthTest();
RenderSystem.depthMask(false);
} else {
RenderSystem.disableDepthTest();
}
BufferBuilder buffer = Tessellator.getInstance().begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE_COLOR);
float pitch = camera.getPitch();
float yaw = camera.getYaw();
int baseColorCached = getColor(hitProgress);
float sizeSpeedFactor = 0.6f + speed * 0.1f;
for (int j = 0; j < count; j++) {
double jAngleOffset = j * (360.0 / count);
double spiralJ = iAge * vertSpeed * 0.5 + j;
for (int i = 0; i <= length; i++) {
double baseAngle = ((i / 2F + iAge * speed * 2.0f) * length + jAngleOffset) % (length * 180);
double radians = Math.toRadians(baseAngle);
float distanceMultiplier = 1.0f + acceleration;
float offset = ((float) (i + length) / (length + length));
double yOffset = calculateYOffset(movement, iAge, i, j, halfHeight, minY, maxY, vertSpeed, vertRange);
reusableMatrices.loadIdentity();
reusableMatrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(pitch));
reusableMatrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(yaw + 180.0F));
double finalWidth = baseWidth * distanceMultiplier * distance;
if (movement.equals("Спираль")) {
double spiralFactor = 1.0 + Math.sin(spiralJ) * 0.3;
finalWidth *= spiralFactor;
}
reusableMatrices.translate(tX + Math.cos(radians) * finalWidth, tY + yOffset, tZ + Math.sin(radians) * finalWidth);
reusableMatrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(-yaw));
reusableMatrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(pitch));
Matrix4f matrix = reusableMatrices.peek().getPositionMatrix();
int blendedColor = blendColors(baseColorCached, getColorStyle((int) (180 * offset)), 0.3f);
int color = applyOpacity(blendedColor, offset * anim);
float particleSize = size * offset * sizeSpeedFactor + bany;
float halfSize = particleSize / 2;
buffer.vertex(matrix, -halfSize, halfSize, 0).texture(0f, 0f).color(color);
buffer.vertex(matrix, halfSize, halfSize, 0).texture(1f, 0f).color(color);
buffer.vertex(matrix, halfSize, -halfSize, 0).texture(1f, 1f).color(color);
buffer.vertex(matrix, -halfSize, -halfSize, 0).texture(0f, 1f).color(color);
}
}
BufferRenderer.drawWithGlobalProgram(buffer.end());
if (canSee) {
RenderSystem.depthMask(true);
}
RenderSystem.enableDepthTest();
RenderSystem.disableBlend();
}
// ============ SOULS THROUGH (Души сквозь) - летают через игрока ============
private void renderSoulsThrough(LivingEntity target, float anim, float hitProgress) {
Camera camera = mc.getEntityRenderDispatcher().camera;
if (camera == null) return;
float delta = mc.getRenderTickCounter().getTickDelta(true);
Vec3d camPos = camera.getPos();
double baseX = interpolate(target.prevX, target.getX(), delta) - camPos.x;
double baseY = interpolate(target.prevY, target.getY(), delta) - camPos.y + target.getHeight() / 2f;
double baseZ = interpolate(target.prevZ, target.getZ(), delta) - camPos.z;
long time = System.currentTimeMillis();
float hurtPC = (float) Math.sin(target.hurtTime * (Math.PI / 25f));
float speed = soulsSpeed.getCurrent() * 50f;
float radius = soulsDistance.getCurrent() * 0.55f;
float size = soulsSize.getCurrent();
int count = (int) soulsCount.getCurrent();
int trailLength = (int) soulsLength.getCurrent() * 15;
double distanceStep = 1.5;
RenderSystem.disableDepthTest();
RenderSystem.enableBlend();
RenderSystem.blendFunc(GlStateManager.SrcFactor.SRC_ALPHA, GlStateManager.DstFactor.ONE);
RenderSystem.setShaderTexture(0, bloomTexture); // Используем bloom как обычные души
RenderSystem.setShader(ShaderProgramKeys.POSITION_TEX_COLOR);
RenderSystem.depthMask(false);
BufferBuilder buffer = Tessellator.getInstance().begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE_COLOR);
float pitch = camera.getPitch();
float yaw = camera.getYaw();
int baseColorCached = getColor(hitProgress);
int redColor = 0xFFFF0000;
float invTrailLength = 1.0f / trailLength;
for (int i = 0; i < trailLength; i++) {
double angle = 0.1f * (time - i * distanceStep) / speed;
double[][] points = new double[count][];
for (int g = 0; g < count; g++) {
double ghostAngle = angle + g * (Math.PI * 2.0 / count);
double s = Math.sin(ghostAngle) * radius;
double c = Math.cos(ghostAngle) * radius;
double zOff = Math.sin(ghostAngle * 1.5) * radius * 0.7;
points[g] = new double[] {baseX + s, baseY + c, baseZ + zOff};
}
float progress = i * invTrailLength;
float sizeFactor = (float) Math.pow(1.0f - progress, 1.1f);
float alphaTrail = anim * (1f - progress * progress) * 0.6f;
float rotation = (float) (time / 5.0 + i * 5) % 360;
int colorWithAlpha = applyOpacity(baseColorCached, alphaTrail);
int redWithAlpha = applyOpacity(redColor, alphaTrail);
int finalColor = blendColors(colorWithAlpha, redWithAlpha, hurtPC);
for (double[] pos : points) {
double dx = pos[0] + camPos.x;
double dy = pos[1] + camPos.y;
double dz = pos[2] + camPos.z;
double distSq = dx * dx + dy * dy + dz * dz;
float distanceScale = (float) (size * 85.0f / Math.max(1, Math.sqrt(distSq)));
float finalSize = distanceScale * sizeFactor;
float halfSize = finalSize / 2;
reusableMatrices.loadIdentity();
reusableMatrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(pitch));
reusableMatrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(yaw + 180.0F));
reusableMatrices.translate(pos[0], pos[1], pos[2]);
reusableMatrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(-yaw));
reusableMatrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(pitch));
reusableMatrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(rotation));
Matrix4f matrix = reusableMatrices.peek().getPositionMatrix();
buffer.vertex(matrix, -halfSize, halfSize, 0).texture(0f, 0f).color(finalColor);
buffer.vertex(matrix, halfSize, halfSize, 0).texture(1f, 0f).color(finalColor);
buffer.vertex(matrix, halfSize, -halfSize, 0).texture(1f, 1f).color(finalColor);
buffer.vertex(matrix, -halfSize, -halfSize, 0).texture(0f, 1f).color(finalColor);
}
}
BufferRenderer.drawWithGlobalProgram(buffer.end());
RenderSystem.depthMask(true);
RenderSystem.enableDepthTest();
RenderSystem.disableBlend();
}
// ============ GHOSTS (Призраки) - летают через игрока ============
private void renderGhosts(LivingEntity target, float anim, float hitProgress) {
Camera camera = mc.getEntityRenderDispatcher().camera;
if (camera == null) return;
float delta = mc.getRenderTickCounter().getTickDelta(true);
Vec3d camPos = camera.getPos();
double baseX = interpolate(target.prevX, target.getX(), delta) - camPos.x;
double baseY = interpolate(target.prevY, target.getY(), delta) - camPos.y + target.getHeight() / 2f;
double baseZ = interpolate(target.prevZ, target.getZ(), delta) - camPos.z;
long time = System.currentTimeMillis();
float hurtPC = (float) Math.sin(target.hurtTime * (Math.PI / 25f));
float speed = ghostSpeed.getCurrent() * 50f;
float radius = ghostRadius.getCurrent() * 0.55f;
float size = ghostSize.getCurrent();
int trailLength = (int) ghostTrailLength.getCurrent() * 15;
double distanceStep = 1.5;
RenderSystem.disableDepthTest();
RenderSystem.enableBlend();
RenderSystem.blendFunc(GlStateManager.SrcFactor.SRC_ALPHA, GlStateManager.DstFactor.ONE);
RenderSystem.setShaderTexture(0, sparkTexture);
RenderSystem.setShader(ShaderProgramKeys.POSITION_TEX_COLOR);
RenderSystem.depthMask(false);
BufferBuilder buffer = Tessellator.getInstance().begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE_COLOR);
float pitch = camera.getPitch();
float yaw = camera.getYaw();
int baseColorCached = getColor(hitProgress);
int redColor = 0xFFFF0000;
float invTrailLength = 1.0f / trailLength;
int numGhosts = (int) ghostCount.getCurrent();
for (int i = 0; i < trailLength; i++) {
double angle = 0.1f * (time - i * distanceStep) / speed;
double[][] points = new double[numGhosts][];
for (int g = 0; g < numGhosts; g++) {
double ghostAngle = angle + g * (Math.PI * 2.0 / numGhosts);
double s = Math.sin(ghostAngle) * radius;
double c = Math.cos(ghostAngle) * radius;
double zOff = Math.sin(ghostAngle * 1.5) * radius * 0.7;
points[g] = new double[] {baseX + s, baseY + c, baseZ + zOff};
}
float progress = i * invTrailLength;
float sizeFactor = (float) Math.pow(1.0f - progress, 1.1f);
float alphaTrail = anim * (1f - progress * progress) * 0.6f;
float rotation = (float) (time / 5.0 + i * 5) % 360;
int colorWithAlpha = applyOpacity(baseColorCached, alphaTrail);
int redWithAlpha = applyOpacity(redColor, alphaTrail);
int finalColor = blendColors(colorWithAlpha, redWithAlpha, hurtPC);
for (double[] pos : points) {
double dx = pos[0] + camPos.x;
double dy = pos[1] + camPos.y;
double dz = pos[2] + camPos.z;
double distSq = dx * dx + dy * dy + dz * dz;
float distanceScale = (float) (size * 85.0f / Math.max(1, Math.sqrt(distSq)));
float finalSize = distanceScale * sizeFactor;
float halfSize = finalSize / 2;
reusableMatrices.loadIdentity();
reusableMatrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(pitch));
reusableMatrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(yaw + 180.0F));
reusableMatrices.translate(pos[0], pos[1], pos[2]);
reusableMatrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(-yaw));
reusableMatrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(pitch));
reusableMatrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(rotation));
Matrix4f matrix = reusableMatrices.peek().getPositionMatrix();
buffer.vertex(matrix, -halfSize, halfSize, 0).texture(0f, 0f).color(finalColor);
buffer.vertex(matrix, halfSize, halfSize, 0).texture(1f, 0f).color(finalColor);
buffer.vertex(matrix, halfSize, -halfSize, 0).texture(1f, 1f).color(finalColor);
buffer.vertex(matrix, -halfSize, -halfSize, 0).texture(0f, 1f).color(finalColor);
}
}
BufferRenderer.drawWithGlobalProgram(buffer.end());
RenderSystem.depthMask(true);
RenderSystem.enableDepthTest();
RenderSystem.disableBlend();
}
private double calculateYOffset(String movement, double iAge, int i, int j, float halfHeight, float minY, float maxY, float vertSpeed, float vertRange) {
double baseY = halfHeight;
switch (movement) {
case "Волна" -> {
double wave = Math.sin(iAge * vertSpeed + j * Math.PI / 2 + i * 0.3) * vertRange;
return baseY + wave;
}
case "Спираль" -> {
double spiral = Math.sin(iAge * vertSpeed * 0.7 + j) * vertRange;
double heightProgress = (Math.sin(iAge * vertSpeed * 0.3 + j * 0.5) + 1) / 2;
return minY + (maxY - minY) * heightProgress + spiral * 0.5;
}
case "Пульс" -> {
double pulse = Math.sin(iAge * vertSpeed) * vertRange;
double individualOffset = Math.sin(j * Math.PI / 2) * 0.2;
return baseY + pulse + individualOffset;
}
default -> {
double sinQuad = Math.sin(Math.toRadians(iAge * 0.7 + i * (j + halfHeight)) * 1.1) / 2;
double adjustedSin = (j % 2 == 0) ? sinQuad : -sinQuad;
return minY + (adjustedSin + 0.5) * (maxY - minY);
}
}
}
// ============ CIRCLE (Кружок) ============
private void renderCircle(LivingEntity target, MatrixStack matrices, float tickDelta, float hitProgress) {
Vec3d camPos = mc.gameRenderer.getCamera().getPos();
double x = MathHelper.lerp(tickDelta, target.lastRenderX, target.getX()) - camPos.x;
double z = MathHelper.lerp(tickDelta, target.lastRenderZ, target.getZ()) - camPos.z;
double y = MathHelper.lerp(tickDelta, target.lastRenderY, target.getY()) - camPos.y +
Math.min(Math.sin(System.currentTimeMillis() / 400.0) + 0.95, target.getHeight());
RenderSystem.disableDepthTest();
RenderSystem.disableCull();
RenderSystem.enableBlend();
RenderSystem.blendFunc(GlStateManager.SrcFactor.SRC_ALPHA, GlStateManager.DstFactor.ONE);
RenderSystem.setShader(ShaderProgramKeys.POSITION_COLOR);
Matrix4f matrix = matrices.peek().getPositionMatrix();
BufferBuilder buffer = Tessellator.getInstance().begin(VertexFormat.DrawMode.TRIANGLE_STRIP, VertexFormats.POSITION_COLOR);
int baseColor = getColor(hitProgress);
float r = ((baseColor >> 16) & 0xFF) / 255f;
float g = ((baseColor >> 8) & 0xFF) / 255f;
float b = (baseColor & 0xFF) / 255f;
float alpha = (float) scale;
float radius = target.getWidth() * 0.8f;
for (float i = 0; i <= Math.PI * 2 + (Math.PI * 5 / 100); i += Math.PI * 5 / 100) {
double vecX = x + radius * Math.cos(i);
double vecZ = z + radius * Math.sin(i);
buffer.vertex(matrix, (float) vecX, (float) (y - Math.cos(System.currentTimeMillis() / 400.0) / 2), (float) vecZ)
.color(r, g, b, 0.01f * alpha);
buffer.vertex(matrix, (float) vecX, (float) y, (float) vecZ)
.color(r, g, b, 1f * alpha);
}
BufferRenderer.drawWithGlobalProgram(buffer.end());
RenderSystem.disableBlend();
RenderSystem.enableDepthTest();
RenderSystem.enableCull();
RenderSystem.blendFunc(GlStateManager.SrcFactor.SRC_ALPHA, GlStateManager.DstFactor.ONE_MINUS_SRC_ALPHA);
}
// ============ UTILS ============
private int applyOpacity(int baseColor, float alpha) {
int r = (baseColor >> 16) & 0xFF;
int g = (baseColor >> 8) & 0xFF;
int b = baseColor & 0xFF;
int a = (int) (255 * Math.min(alpha, 1f));
return (a << 24) | (r << 16) | (g << 8) | b;
}
private int blendColors(int color1, int color2, float ratio) {
int r1 = (color1 >> 16) & 0xFF;
int g1 = (color1 >> 8) & 0xFF;
int b1 = color1 & 0xFF;
int r2 = (color2 >> 16) & 0xFF;
int g2 = (color2 >> 8) & 0xFF;
int b2 = color2 & 0xFF;
int r = (int) (r1 + (r2 - r1) * ratio);
int g = (int) (g1 + (g2 - g1) * ratio);
int b = (int) (b1 + (b2 - b1) * ratio);
return (0xFF << 24) | (r << 16) | (g << 8) | b;
}
private int setAlpha(int color, int alpha) {
return (alpha << 24) | (color & 0x00FFFFFF);
}
// ============ CRYSTALS (Кристаллы) ============
private void renderCrystals(LivingEntity target, MatrixStack ms, float anim, float hitProgress) {
if (target == null) return;
if (crystalList.isEmpty() || target != lastCrystalTarget) {
createCrystals();
lastCrystalTarget = target;
}
RenderSystem.enableDepthTest();
float delta = mc.getRenderTickCounter().getTickDelta(true);
Vec3d camPos = mc.gameRenderer.getCamera().getPos();
double tX = MathHelper.lerp(delta, target.lastRenderX, target.getX()) - camPos.x;
double tY = MathHelper.lerp(delta, target.lastRenderY, target.getY()) - camPos.y;
double tZ = MathHelper.lerp(delta, target.lastRenderZ, target.getZ()) - camPos.z;
float rotSpeed = crystalSpeed.getCurrent();
crystalRotationAngle = (crystalRotationAngle + rotSpeed) % 360;
ms.push();
ms.translate(tX, tY, tZ);
ms.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(crystalRotationAngle));
Camera camera = mc.gameRenderer.getCamera();
int baseColor = getColor(hitProgress);
float size = crystalSize.getCurrent();
for (CrystalData crystal : crystalList) {
renderCrystal(ms, crystal, baseColor, anim, camera, size);
}
ms.pop();
RenderSystem.enableDepthTest();
}
private void createCrystals() {
crystalList.clear();
// 14 кристаллов как в оригинале
crystalList.add(new CrystalData(new Vec3d(0, 0.85, 0.8), new Vec3d(-49, 0, 40)));
crystalList.add(new CrystalData(new Vec3d(0.2, 0.85, -0.675), new Vec3d(35, 0, -30)));
crystalList.add(new CrystalData(new Vec3d(0.6, 1.35, 0.6), new Vec3d(-30, 0, 35)));
crystalList.add(new CrystalData(new Vec3d(-0.74, 1.05, 0.4), new Vec3d(-25, 0, -30)));
crystalList.add(new CrystalData(new Vec3d(0.74, 0.95, -0.4), new Vec3d(0, 0, 0)));
crystalList.add(new CrystalData(new Vec3d(-0.475, 0.85, -0.375), new Vec3d(30, 0, -25)));
crystalList.add(new CrystalData(new Vec3d(0, 1.35, -0.6), new Vec3d(45, 0, 0)));
crystalList.add(new CrystalData(new Vec3d(0.85, 0.7, 0.1), new Vec3d(-30, 0, 30)));
crystalList.add(new CrystalData(new Vec3d(-0.7, 1.35, -0.3), new Vec3d(0, 0, 0)));
crystalList.add(new CrystalData(new Vec3d(-0.3, 1.35, 0.55), new Vec3d(0, 0, 0)));
crystalList.add(new CrystalData(new Vec3d(-0.5, 0.7, 0.7), new Vec3d(0, 0, 0)));
crystalList.add(new CrystalData(new Vec3d(0.5, 0.7, 0.7), new Vec3d(0, 0, 0)));
crystalList.add(new CrystalData(new Vec3d(-0.7, 0.75, 0), new Vec3d(0, 0, 0)));
crystalList.add(new CrystalData(new Vec3d(-0.2, 0.65, -0.7), new Vec3d(0, 0, 0)));
}
private void renderCrystal(MatrixStack ms, CrystalData crystal, int baseColor, float anim, Camera camera, float size) {
ms.push();
ms.translate(crystal.position.x, crystal.position.y, crystal.position.z);
float pulsation = 1.0f + (float) (Math.sin(System.currentTimeMillis() / 500.0) * 0.1f);
ms.scale(pulsation, pulsation, pulsation);
float selfRotation = (System.currentTimeMillis() % 36000) / 100.0f * crystal.rotationSpeed;
ms.multiply(RotationAxis.POSITIVE_X.rotationDegrees((float) crystal.rotation.x));
ms.multiply(RotationAxis.POSITIVE_Y.rotationDegrees((float) crystal.rotation.y + selfRotation));
ms.multiply(RotationAxis.POSITIVE_Z.rotationDegrees((float) crystal.rotation.z));
RenderSystem.disableCull();
RenderSystem.enableBlend();
RenderSystem.blendFunc(GlStateManager.SrcFactor.SRC_ALPHA, GlStateManager.DstFactor.ONE_MINUS_SRC_ALPHA);
RenderSystem.setShader(ShaderProgramKeys.POSITION_COLOR);
// Внутреннее свечение
RenderSystem.blendFunc(GlStateManager.SrcFactor.SRC_ALPHA, GlStateManager.DstFactor.ONE);
drawCrystalShape(ms, baseColor, 0.15f, true, anim, size);
// Основной кристалл
RenderSystem.blendFunc(GlStateManager.SrcFactor.SRC_ALPHA, GlStateManager.DstFactor.ONE_MINUS_SRC_ALPHA);
drawCrystalShape(ms, baseColor, 0.4f, true, anim, size);
// Внешнее свечение
RenderSystem.depthMask(false);
RenderSystem.blendFunc(GlStateManager.SrcFactor.SRC_ALPHA, GlStateManager.DstFactor.ONE);
ms.push();
ms.scale(1.3f, 1.3f, 1.3f);
drawCrystalShape(ms, baseColor, 0.2f, true, anim, size);
ms.pop();
// Bloom сфера
drawBloomSphere(ms, baseColor, anim, camera, size);
RenderSystem.depthMask(true);
RenderSystem.disableBlend();
RenderSystem.enableCull();
ms.pop();
}
private void drawCrystalShape(MatrixStack ms, int baseColor, float alpha, boolean filled, float anim, float size) {
BufferBuilder buffer = Tessellator.getInstance().begin(
filled ? VertexFormat.DrawMode.TRIANGLES : VertexFormat.DrawMode.DEBUG_LINES,
VertexFormats.POSITION_COLOR
);
float s = size;
float h_prism = size * 1.2f;
float h_pyramid = size * 2.0f;
int numSides = 6; // Меньше граней для более гладкого вида
java.util.List<Vec3d> topVertices = new java.util.ArrayList<>();
java.util.List<Vec3d> bottomVertices = new java.util.ArrayList<>();
for (int i = 0; i < numSides; i++) {
float angle = (float) (2 * Math.PI * i / numSides);
float x = (float) (s * Math.cos(angle));
float z = (float) (s * Math.sin(angle));
topVertices.add(new Vec3d(x, h_prism / 2, z));
bottomVertices.add(new Vec3d(x, -h_prism / 2, z));
}
Vec3d vTop = new Vec3d(0, h_prism / 2 + h_pyramid, 0);
Vec3d vBottom = new Vec3d(0, -h_prism / 2 - h_pyramid, 0);
int finalColor = setAlpha(baseColor, (int) (alpha * 255 * anim));
// Боковые грани призмы
for (int i = 0; i < numSides; i++) {
Vec3d v1 = bottomVertices.get(i);
Vec3d v2 = bottomVertices.get((i + 1) % numSides);
Vec3d v3 = topVertices.get((i + 1) % numSides);
Vec3d v4 = topVertices.get(i);
if (filled) {
drawTriangle(ms, buffer, v1, v2, v3, finalColor);
drawTriangle(ms, buffer, v1, v3, v4, finalColor);
}
}
// Верхняя пирамида
for (int i = 0; i < numSides; i++) {
Vec3d v1 = topVertices.get(i);
Vec3d v2 = topVertices.get((i + 1) % numSides);
if (filled) drawTriangle(ms, buffer, vTop, v1, v2, finalColor);
}
// Нижняя пирамида
for (int i = 0; i < numSides; i++) {
Vec3d v1 = bottomVertices.get(i);
Vec3d v2 = bottomVertices.get((i + 1) % numSides);
if (filled) drawTriangle(ms, buffer, vBottom, v2, v1, finalColor);
}
BufferRenderer.drawWithGlobalProgram(buffer.end());
}
private void drawTriangle(MatrixStack ms, BufferBuilder bb, Vec3d v1, Vec3d v2, Vec3d v3, int color) {
Matrix4f matrix = ms.peek().getPositionMatrix();
bb.vertex(matrix, (float)v1.x, (float)v1.y, (float)v1.z).color(color);
bb.vertex(matrix, (float)v2.x, (float)v2.y, (float)v2.z).color(color);
bb.vertex(matrix, (float)v3.x, (float)v3.y, (float)v3.z).color(color);
}
private void drawBloomSphere(MatrixStack ms, int baseColor, float anim, Camera camera, float size) {
RenderSystem.setShader(ShaderProgramKeys.POSITION_TEX_COLOR);
RenderSystem.setShaderTexture(0, bloomTexture);
RenderSystem.enableBlend();
RenderSystem.blendFunc(GlStateManager.SrcFactor.SRC_ALPHA, GlStateManager.DstFactor.ONE);
RenderSystem.depthMask(false);
int bloomColor = setAlpha(baseColor, (int) (0.5f * 25 * anim));
float bloomSize = size * 15.0f;
float pitch = camera.getPitch();
float yaw = camera.getYaw();
int segments = 6;
for (int i = 0; i < segments; i++) {
ms.push();
float angle = (360.0f / segments) * i;
ms.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(angle));
ms.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(-yaw));
ms.multiply(RotationAxis.POSITIVE_X.rotationDegrees(pitch));
Matrix4f matrix = ms.peek().getPositionMatrix();
BufferBuilder buffer = Tessellator.getInstance().begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE_COLOR);
buffer.vertex(matrix, -bloomSize / 2, -bloomSize / 2, 0).texture(0, 1).color(bloomColor);
buffer.vertex(matrix, bloomSize / 2, -bloomSize / 2, 0).texture(1, 1).color(bloomColor);
buffer.vertex(matrix, bloomSize / 2, bloomSize / 2, 0).texture(1, 0).color(bloomColor);
buffer.vertex(matrix, -bloomSize / 2, bloomSize / 2, 0).texture(0, 0).color(bloomColor);
BufferRenderer.drawWithGlobalProgram(buffer.end());
ms.pop();
}
RenderSystem.depthMask(true);
RenderSystem.blendFunc(GlStateManager.SrcFactor.SRC_ALPHA, GlStateManager.DstFactor.ONE_MINUS_SRC_ALPHA);
}
private static class CrystalData {
final Vec3d position;
final Vec3d rotation;
final float rotationSpeed;
CrystalData(Vec3d position, Vec3d rotation) {
this.position = position;
this.rotation = rotation;
this.rotationSpeed = 0.5f + (float)(Math.random() * 1.5f);
}
}
}
}