Вот
package dev.Potoshik.client.managers.module.impl.render;
import dev.Potoshik.client.api.events.orbit.EventHandler;
import dev.Potoshik.client.managers.events.player.AttackEvent;
import dev.Potoshik.client.managers.events.player.JumpEvent;
import dev.Potoshik.client.managers.events.player.MoveInputEvent;
import dev.Potoshik.client.managers.events.player.UpdateEvent;
import dev.Potoshik.client.managers.events.render.Render3DLastEvent;
import dev.Potoshik.client.managers.module.Category;
import dev.Potoshik.client.managers.module.Module;
import dev.Potoshik.client.managers.module.ModuleInfo;
import dev.Potoshik.client.managers.module.impl.render.InterFace;
import dev.Potoshik.client.managers.module.settings.impl.BooleanSetting;
import dev.Potoshik.client.managers.module.settings.impl.ColorSetting;
import dev.Potoshik.client.managers.module.settings.impl.ModeSetting;
import dev.Potoshik.client.managers.module.settings.impl.MultiBooleanSetting;
import dev.Potoshik.client.managers.module.settings.impl.SliderSetting;
import dev.Potoshik.client.utils.render.color.ColorUtil;
import dev.Potoshik.client.utils.render.draw.RenderUtil3D;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.vector.Vector3d;
import org.lwjgl.opengl.GL11;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import static dev.Potoshik.client.api.interfaces.IRender.BUFFER;
import static dev.Potoshik.client.api.interfaces.IRender.TESSELLATOR;
@ModuleInfo(name = "Hitwave", category = Category.RENDER, desc = "Волна по блокам при ударе по игроку")
public class Shockwave extends Module {
private final ModeSetting animation = new ModeSetting(this, "Анимация", "Плавная", "Пульсирующая", "Множественная", "Ускорение", "Эластичная", "Кольца");
private final SliderSetting radius = new SliderSetting(this, "Радиус", 8.0F, 3.0F, 20.0F, 0.5F);
private final SliderSetting speed = new SliderSetting(this, "Скорость", 0.15F, 0.05F, 0.5F, 0.01F);
private final SliderSetting height = new SliderSetting(this, "Высота", 2.0F, 0.0F, 5.0F, 0.5F);
private final SliderSetting waveCount = new SliderSetting(this, "Количество волн", 3.0F, 2.0F, 5.0F, 1.0F)
.setVisible(() -> animation.is("Множественная") || animation.is("Кольца"));
private final SliderSetting pulseSpeed = new SliderSetting(this, "Скорость пульса", 0.05F, 0.01F, 0.2F, 0.01F)
.setVisible(() -> animation.is("Пульсирующая"));
private final BooleanSetting onlyPlayers = new BooleanSetting(this, "Только игроки", true);
private final BooleanSetting fill = new BooleanSetting(this, "Заливка", true);
private final ColorSetting color = new ColorSetting(this, "Цвет");
// Настройки типов действий крутые всякие
private final MultiBooleanSetting actionTypes = new MultiBooleanSetting(this, "Типы действий",
BooleanSetting.of("Удар", true),
BooleanSetting.of("Прыжок", false),
BooleanSetting.of("Ходьба", false),
BooleanSetting.of("Приземление", false));
private final SliderSetting walkInterval = new SliderSetting(this, "Интервал ходьбы", 10.0F, 5.0F, 30.0F, 1.0F)
.setVisible(() -> actionTypes.getValue("Ходьба"));
private final List<Wave> waves = new ArrayList<>();
private boolean wasOnGround = true;
private int walkTicks = 0;
private static class Wave {
Vector3d center;
float currentRadius;
float maxRadius;
float speed;
float baseSpeed;
float height;
long startTime;
int color;
String animationType;
float pulsePhase;
int waveIndex; // Для множественных волн хавает фпс
Wave(Vector3d center, float maxRadius, float speed, float height, int color, String animationType, int waveIndex) {
this.center = center;
this.currentRadius = 0.0F;
this.maxRadius = maxRadius;
this.speed = speed;
this.baseSpeed = speed;
this.height = height;
this.startTime = System.currentTimeMillis();
this.color = color;
this.animationType = animationType;
this.pulsePhase = 0.0F;
this.waveIndex = waveIndex;
}
void update() {
pulsePhase += 0.1F;
if ("Плавная".equals(animationType)) {
currentRadius += speed;
} else if ("Пульсирующая".equals(animationType)) {
// Пульсирующее движение с ускорением/замедлением +-
float pulse = (float) (Math.sin(pulsePhase) * 0.3F + 1.0F);
currentRadius += speed * pulse;
} else if ("Ускорение".equals(animationType)) {
// Ускорение по мере распространения фигня если честно
float acceleration = 1.0F + (currentRadius / maxRadius) * 2.0F;
currentRadius += speed * acceleration;
} else if ("Эластичная".equals(animationType)) {
// Эластичный эффект с отскоком
float elastic = (float) (1.0F + Math.sin(pulsePhase * 2.0F) * 0.2F);
currentRadius += speed * elastic;
} else if ("Множественная".equals(animationType) || "Кольца".equals(animationType)) {
// Для множественных волн - каждая начинается с задержкой
float delay = waveIndex * 1.5F;
if (currentRadius < delay) {
currentRadius = delay;
} else {
currentRadius += speed;
}
}
}
boolean isFinished() {
return currentRadius >= maxRadius;
}
float getAlpha() {
float progress = currentRadius / maxRadius;
if ("Пульсирующая".equals(animationType)) {
// Пульсирующая альфа
float pulseAlpha = (float) (Math.sin(pulsePhase * 2.0F) * 0.3F + 0.7F);
return Math.max(0.0F, (1.0F - progress * 0.8F) * pulseAlpha);
} else if ("Эластичная".equals(animationType)) {
// Эластичное затухание
float elasticAlpha = (float) (1.0F - Math.pow(progress, 1.5F));
return Math.max(0.0F, elasticAlpha * 0.9F);
} else if ("Множественная".equals(animationType) || "Кольца".equals(animationType)) {
// Для множественных волн - каждая имеет свою альфу
float waveProgress = (currentRadius - (waveIndex * 1.5F)) / (maxRadius - (waveIndex * 1.5F));
if (waveProgress < 0) waveProgress = 0;
return Math.max(0.0F, (1.0F - waveProgress * 0.9F));
} else {
// Плавное затухание
return Math.max(0.0F, 1.0F - progress * 0.8F);
}
}
float getRenderRadius() {
if ("Пульсирующая".equals(animationType)) {
// Пульсирующий радиус
float pulse = (float) (Math.sin(pulsePhase * 1.5F) * 0.15F + 1.0F);
return currentRadius * pulse;
} else if ("Эластичная".equals(animationType)) {
// Эластичный радиус ЗАФИКСИ!
float elastic = (float) (1.0F + Math.sin(pulsePhase * 3.0F) * 0.1F);
return currentRadius * elastic;
} else {
return currentRadius;
}
}
}
private void createWave(Vector3d center) {
// Получаем цвет из настройки, если доступен InterFace - используем цвет темы как fallback
Integer colorValue = color.getValue();
int waveColor;
if (colorValue != null) {
waveColor = colorValue;
} else {
// Если цвет не установлен, пытаемся получить цвет темы
try {
if (InterFace.getInstance() != null) {
waveColor = InterFace.getInstance().themeColor();
} else {
waveColor = 0xFF00FF; // Fallback цвет
}
} catch (Exception e) {
// Если InterFace еще не инициализирован, используем дефолтный цвет
waveColor = 0xFF00FF;
}
}
String animType = animation.getValue();
if (animType.equals("Множественная") || animType.equals("Кольца")) {
// Создаем несколько волн с задержкой
int count = Math.round(waveCount.getValue());
for (int i = 0; i < count; i++) {
waves.add(new Wave(center, radius.getValue(), speed.getValue(), height.getValue(), waveColor, animType, i));
}
} else {
// Одна волна
waves.add(new Wave(center, radius.getValue(), speed.getValue(), height.getValue(), waveColor, animType, 0));
}
}
@EventHandler
public void onAttack(AttackEvent event) {
if (!actionTypes.getValue("Удар")) return;
if (event.getTarget() == null || event.getTarget() == mc.player) return;
if (event.getTarget() instanceof LivingEntity) {
LivingEntity target = (LivingEntity) event.getTarget();
if (onlyPlayers.getValue() && !(target instanceof PlayerEntity)) return;
Vector3d center = target.getPositionVec().add(0, target.getHeight() / 2.0, 0);
createWave(center);
}
}
@EventHandler
public void onJump(JumpEvent event) {
if (!actionTypes.getValue("Прыжок")) return;
if (mc.player == null) return;
Vector3d center = mc.player.getPositionVec().add(0, mc.player.getHeight() / 2.0, 0);
createWave(center);
}
@EventHandler
public void onUpdate(UpdateEvent event) {
if (mc.player == null) return;
// Обновление волн
Iterator<Wave> iterator = waves.iterator();
while (iterator.hasNext()) {
Wave wave = iterator.next();
wave.update();
if (wave.isFinished()) {
iterator.remove();
}
}
// Проверка приземления
if (actionTypes.getValue("Приземление")) {
boolean isOnGround = mc.player.isOnGround();
if (!wasOnGround && isOnGround) {
// Игрок приземлился
Vector3d center = mc.player.getPositionVec().add(0, mc.player.getHeight() / 2.0, 0);
createWave(center);
}
wasOnGround = isOnGround;
}
// Проверка ходьбы
if (actionTypes.getValue("Ходьба")) {
if (mc.player.isOnGround() && (Math.abs(mc.player.motion.x) > 0.01 || Math.abs(mc.player.motion.z) > 0.01)) {
walkTicks++;
int interval = Math.round(walkInterval.getValue());
if (walkTicks >= interval) {
walkTicks = 0;
Vector3d center = mc.player.getPositionVec().add(0, mc.player.getHeight() / 2.0, 0);
createWave(center);
}
} else {
walkTicks = 0;
}
}
}
@EventHandler
public void onRender(Render3DLastEvent event) {
if (waves.isEmpty() || mc.world == null || mc.player == null) return;
float partialTicks = event.getPartialTicks();
for (Wave wave : waves) {
renderWave(event, wave, partialTicks);
}
}
private void renderWave(Render3DLastEvent event, Wave wave, float partialTicks) {
float currentRadius = wave.getRenderRadius();
float alpha = wave.getAlpha();
if (alpha <= 0.0F || currentRadius <= 0.0F) return;
// Вычисляем текущий радиус с учетом частичных тиков
float renderRadius = currentRadius + (wave.baseSpeed * partialTicks);
// Для колец - показываем только определенные радиусы
if (wave.animationType.equals("Кольца")) {
float ringSpacing = wave.maxRadius / Math.round(waveCount.getValue());
float ringRadius = (wave.waveIndex + 1) * ringSpacing;
if (Math.abs(renderRadius - ringRadius) > 0.5F) {
return; // Показываем только кольца на определенных радиусах
}
}
// Получаем блоки в радиусе волны
BlockPos centerPos = new BlockPos(wave.center);
int radiusInt = (int) Math.ceil(renderRadius);
// Высота волны (блоки выше и ниже центра)
int heightInt = (int) Math.ceil(wave.height);
List<BlockPos> blocksToRender = new ArrayList<>();
// Проходим по всем блокам в радиусе
for (int x = -radiusInt; x <= radiusInt; x++) {
for (int z = -radiusInt; z <= radiusInt; z++) {
for (int y = -heightInt; y <= heightInt; y++) {
BlockPos blockPos = centerPos.add(x, y, z);
// Проверяем расстояние от центра до блока
double distX = (blockPos.getX() + 0.5) - wave.center.x;
double distZ = (blockPos.getZ() + 0.5) - wave.center.z;
double distY = (blockPos.getY() + 0.5) - wave.center.y;
// Расстояние по горизонтали
double horizontalDist = Math.sqrt(distX * distX + distZ * distZ);
// Проверяем, находится ли блок на волне (с допуском)
float waveThickness = 0.8F; // Толщина волны
if (Math.abs(horizontalDist - renderRadius) <= waveThickness &&
Math.abs(distY) <= wave.height) {
// Проверяем, что блок существует и не воздух
if (mc.world.getBlockState(blockPos).isAir()) continue;
blocksToRender.add(blockPos);
}
}
}
}
if (blocksToRender.isEmpty()) return;
// Цвета с учетом альфы
int outlineColor = ColorUtil.multAlpha(wave.color, alpha);
int fillColor = fill.getValue() ? ColorUtil.multAlpha(ColorUtil.multDark(wave.color, 0.15F), alpha * 0.3F) : 0;
int decussationColor = ColorUtil.multAlpha(ColorUtil.multDark(wave.color, 0.4F), alpha * 0.5F);
RenderUtil3D.setup3dForBlockPosNew(event, () -> {
GL11.glEnable(GL11.GL_LINE_SMOOTH);
GL11.glHint(GL11.GL_LINE_SMOOTH_HINT, GL11.GL_NICEST);
GL11.glLineWidth(2.0F);
GL11.glDisable(GL11.GL_DEPTH_TEST);
for (BlockPos blockPos : blocksToRender) {
double blockX = blockPos.getX() + 0.5;
double blockY = blockPos.getY() + 0.5;
double blockZ = blockPos.getZ() + 0.5;
AxisAlignedBB blockBB = new AxisAlignedBB(
blockX - 0.5, blockY - 0.5, blockZ - 0.5,
blockX + 0.5, blockY + 0.5, blockZ + 0.5
);
// Проверяем, не пересекается ли блок с игроком
if (blockBB.intersects(mc.player.getBoundingBox())) continue;
RenderUtil3D.drawCanisterBox(
event.getMatrix(),
BUFFER,
TESSELLATOR,
blockBB,
true,
true,
fill.getValue(),
outlineColor,
decussationColor,
fillColor
);
}
GL11.glLineWidth(1.0F);
GL11.glHint(GL11.GL_LINE_SMOOTH_HINT, GL11.GL_DONT_CARE);
GL11.glDisable(GL11.GL_LINE_SMOOTH);
GL11.glEnable(GL11.GL_DEPTH_TEST);
}, true, true);
}
@override
public void onDisable() {
super.onDisable();
waves.clear();
}
}