package wixx.modules.impl.visual;
import com.google.common.eventbus.Subscribe;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.systems.RenderSystem;
import wixx.events.EventChangeWorld;
import wixx.events.EventPreRender3D;
import wixx.modules.api.Category;
import wixx.modules.api.Module;
import wixx.modules.api.ModuleRegister;
import wixx.modules.settings.impl.CheckBoxSetting;
import wixx.modules.settings.impl.SliderSetting;
import wixx.utils.animations.easing.CompactAnimation;
import wixx.utils.animations.easing.Easing;
import wixx.utils.math.MathUtility;
import wixx.utils.math.TimerUtility;
import wixx.utils.render.color.ColorUtility;
import wixx.utils.render.engine2d.RectUtility;
import lombok.Getter;
import net.minecraft.client.entity.player.ClientPlayerEntity;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.MathHelper;
import org.joml.Math;
import org.joml.Vector3d;
import org.lwjgl.opengl.GL11;
import java.util.ArrayList;
import java.util.List;
@ModuleRegister(name = "FireFlies", category = Category.Visual)
public class FireFly extends Module {
private final List<FireFlyEntity> particles = new ArrayList<>();
private final SliderSetting count = new SliderSetting("Количество", 100, 10, 300, 10);
private final SliderSetting speed = new SliderSetting("Скорость", 0.15f, 0.05f, 0.5f, 0.05f);
private final SliderSetting radius = new SliderSetting("Радиус спавна", 25, 10, 50, 5);
private final SliderSetting trailLength = new SliderSetting("Длина шлейфа", 20, 5, 40, 5);
public final CheckBoxSetting randomColor = new CheckBoxSetting("Рандомный цвет", true);
public final CheckBoxSetting optimization = new CheckBoxSetting("Оптимизация", true);
private final ResourceLocation texture = new ResourceLocation("eva/images/firefly.png");
public FireFly() {
addSettings(count, speed, radius, trailLength, randomColor, optimization);
}
@override
public boolean onEnable() {
super.onEnable();
particles.clear();
return false;
}
@override
public void onDisable() {
super.onDisable();
particles.clear();
}
private void spawnParticle(ClientPlayerEntity player) {
double distance = MathUtility.random(5, radius.getValue().floatValue());
double yawRad = Math.toRadians(MathUtility.random(0, 360));
double xOffset = -Math.sin(yawRad) * distance;
double zOffset = Math.cos(yawRad) * distance;
double yOffset = MathUtility.random(-5, 10);
double velocitySpeed = speed.getValue().floatValue();
double velocityYaw = Math.toRadians(MathUtility.random(0, 360));
double velocityPitch = Math.toRadians(MathUtility.random(-30, 30));
Vector3d initialVelocity = new Vector3d(
-Math.sin(velocityYaw) * Math.cos(velocityPitch) * velocitySpeed,
Math.sin(velocityPitch) * velocitySpeed * 0.5,
Math.cos(velocityYaw) * Math.cos(velocityPitch) * velocitySpeed
);
particles.add(new FireFlyEntity(
new Vector3d(player.getPosX() + xOffset, player.getPosY() + yOffset, player.getPosZ() + zOffset),
initialVelocity,
particles.size(),
ColorUtility.random().hashCode()
));
}
@Subscribe
public void onChange(EventChangeWorld e) {
particles.clear();
}
@Subscribe
public void onPreRender(EventPreRender3D event) {
ClientPlayerEntity player = mc.player;
if (player == null) return;
particles.removeIf(particle ->
particle.time.isReached(8000) ||
particle.position.distance(player.getPosX(), player.getPosY(), player.getPosZ()) >= 60
);
while (particles.size() < count.getValue().intValue()) {
spawnParticle(player);
}
MatrixStack matrix = event.getMatrix();
boolean lightEnabled = GL11.glIsEnabled(GL11.GL_LIGHTING);
RenderSystem.pushMatrix();
matrix.push();
RenderSystem.enableBlend();
RenderSystem.disableAlphaTest();
RenderSystem.depthMask(false);
RenderSystem.disableCull();
if (lightEnabled) {
RenderSystem.disableLighting();
}
GL11.glShadeModel(GL11.GL_SMOOTH);
RenderSystem.blendFuncSeparate(
GlStateManager.SourceFactor.SRC_ALPHA,
GlStateManager.DestFactor.ONE,
GlStateManager.SourceFactor.ONE,
GlStateManager.DestFactor.ZERO
);
RectUtility.bindTexture(texture);
for (FireFlyEntity particle : particles) {
particle.update();
if (optimization.getValue()) {
if (player.getDistanceSq(particle.position.x, particle.position.y, particle.position.z) > 2500) { // 50 блоков
particle.update();
continue;
}
}
double distSq = player.getDistanceSq(particle.position.x, particle.position.y, particle.position.z);
if (!optimization.getValue() || distSq < 1600) {
renderTrail(matrix, particle);
}
renderParticle(matrix, particle);
}
cleanupRenderState(lightEnabled, matrix);
}
private void renderTrail(MatrixStack matrix, FireFlyEntity particle) {
List<Vector3d> trail = particle.getTrail();
if (trail.size() < 2) return;
updateParticleAlpha(particle);
int baseAlpha = (int) particle.getAlpha().getValue();
int color = randomColor.getValue() ?
particle.getColor() :
ColorUtility.getColor(particle.index * 50);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE);
for (int i = 0; i < trail.size(); i++) {
if (optimization.getValue() && i % 2 != 0) continue;
Vector3d pos = trail.get(i);
float fade = (float) i / (float) trail.size();
float size = 0.15f * fade;
int trailAlpha = (int) (baseAlpha * fade * 0.8f);
int trailColor = ColorUtility.reAlphaInt(color, trailAlpha);
matrix.push();
RectUtility.setupOrientationMatrix(matrix, (float) pos.x, (float) pos.y, (float) pos.z);
matrix.rotate(mc.getRenderManager().getCameraOrientation());
RectUtility.drawRect(matrix, -size, -size, size, size,
trailColor, trailColor, trailColor, trailColor, true, true);
matrix.pop();
if (i % 3 == 0 && fade > 0.3f) {
int miniParticleCount = optimization.getValue() ? 1 : 2 + (int)(Math.random() * 3);
for (int j = 0; j < miniParticleCount; j++) {
double offsetX = (Math.random() - 0.5) * 0.3;
double offsetY = (Math.random() - 0.5) * 0.3;
double offsetZ = (Math.random() - 0.5) * 0.3;
float miniSize = 0.04f + (float)(Math.random() * 0.03f);
int miniAlpha = (int) (trailAlpha * 0.6f);
int miniColor = ColorUtility.reAlphaInt(color, miniAlpha);
matrix.push();
RectUtility.setupOrientationMatrix(matrix,
(float) (pos.x + offsetX),
(float) (pos.y + offsetY),
(float) (pos.z + offsetZ));
matrix.rotate(mc.getRenderManager().getCameraOrientation());
RectUtility.drawRect(matrix, -miniSize, -miniSize, miniSize, miniSize,
miniColor, miniColor, miniColor, miniColor, true, true);
matrix.pop();
}
}
}
}
private void renderParticle(MatrixStack matrix, FireFlyEntity particle) {
updateParticleAlpha(particle);
int baseAlpha = (int) particle.getAlpha().getValue();
int pulseAlpha = particle.getPulseAlpha();
int finalAlpha = java.lang.Math.min(baseAlpha, pulseAlpha);
int color = randomColor.getValue() ?
particle.getColor() :
ColorUtility.getColor(particle.index * 50);
Vector3d pos = particle.getPosition();
matrix.push();
RectUtility.setupOrientationMatrix(matrix, (float) pos.x, (float) pos.y, (float) pos.z);
matrix.rotate(mc.getRenderManager().getCameraOrientation());
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE);
float glowSize = 0.35f;
int glowColor = ColorUtility.reAlphaInt(color, (int)(finalAlpha * 0.6f));
RectUtility.drawRect(matrix, -glowSize, -glowSize, glowSize, glowSize,
glowColor, glowColor, glowColor, glowColor, true, true);
float mainSize = 0.22f;
int mainColor = ColorUtility.reAlphaInt(color, finalAlpha);
RectUtility.drawRect(matrix, -mainSize, -mainSize, mainSize, mainSize,
mainColor, mainColor, mainColor, mainColor, true, true);
float coreSize = 0.10f;
int coreColor = ColorUtility.reAlphaInt(0xFFFFFFFF, finalAlpha);
RectUtility.drawRect(matrix, -coreSize, -coreSize, coreSize, coreSize,
coreColor, coreColor, coreColor, coreColor, true, true);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
matrix.pop();
}
private void updateParticleAlpha(FireFlyEntity particle) {
long fadeInDuration = particle.alpha.getDuration();
long fadeOutStart = 8000 - fadeInDuration;
if (particle.getAlpha().getValue() < 255 && !particle.time.isReached(fadeInDuration)) {
particle.getAlpha().run(255);
}
if (particle.getAlpha().getValue() > 0 && particle.time.isReached(fadeOutStart)) {
particle.getAlpha().run(0);
}
}
private void cleanupRenderState(boolean lightEnabled, MatrixStack matrix) {
RenderSystem.blendFuncSeparate(
GlStateManager.SourceFactor.SRC_ALPHA,
GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA,
GlStateManager.SourceFactor.ONE,
GlStateManager.DestFactor.ZERO
);
GlStateManager.clearCurrentColor();
GL11.glShadeModel(GL11.GL_FLAT);
if (lightEnabled) {
RenderSystem.enableLighting();
}
RenderSystem.enableCull();
RenderSystem.depthMask(true);
RenderSystem.enableAlphaTest();
matrix.pop();
RenderSystem.popMatrix();
}
@Getter
private class FireFlyEntity {
private final int index;
private final TimerUtility time = new TimerUtility();
private final CompactAnimation alpha = new CompactAnimation(Easing.EASE_OUT_QUAD, 500);
private final int color;
private final Vector3d position;
private final Vector3d velocity;
private final List<Vector3d> trail = new ArrayList<>();
public FireFlyEntity(Vector3d position, Vector3d velocity, int index, int color) {
this.position = position;
this.velocity = velocity;
this.index = index;
this.color = color;
this.time.reset();
this.trail.add(new Vector3d(position.x, position.y, position.z));
}
public AxisAlignedBB getBounds() {
double s = 0.5;
return new AxisAlignedBB(position.x - s, position.y - s, position.z - s,
position.x + s, position.y + s, position.z + s);
}
public void update() {
double randomness = 0.01;
velocity.x += (java.lang.Math.random() - 0.5) * randomness;
velocity.y += (java.lang.Math.random() - 0.5) * randomness;
velocity.z += (java.lang.Math.random() - 0.5) * randomness;
double maxSpeed = speed.getValue().floatValue() * 1.5;
velocity.x = MathHelper.clamp(velocity.x, -maxSpeed, maxSpeed);
velocity.y = MathHelper.clamp(velocity.y, -maxSpeed, maxSpeed);
velocity.z = MathHelper.clamp(velocity.z, -maxSpeed, maxSpeed);
position.x += velocity.x;
position.y += velocity.y;
position.z += velocity.z;
Vector3d lastTrailPos = trail.isEmpty() ? null : trail.get(trail.size() - 1);
if (lastTrailPos == null || position.distanceSquared(lastTrailPos.x, lastTrailPos.y, lastTrailPos.z) > 0.005) {
trail.add(new Vector3d(position.x, position.y, position.z));
}
int maxTrailLength = trailLength.getValue().intValue();
while (trail.size() > maxTrailLength) {
trail.remove(0);
}
}
public int getPulseAlpha() {
double pulse = (java.lang.Math.sin(time.getTime() / 300.0) + 1.0) / 2.0;
return (int) (pulse * 255);
}
}
}
на тут даже лучше