generated from MrSphay/codex-agent-repository-kit
190 lines
7.8 KiB
Java
190 lines
7.8 KiB
Java
package com.vinlanx.explosionoverhaul.client;
|
|
|
|
import com.vinlanx.explosionoverhaul.Config;
|
|
import com.vinlanx.explosionoverhaul.SmokeParticleOptions;
|
|
import java.awt.Color;
|
|
import java.util.Random;
|
|
import net.minecraft.client.Minecraft;
|
|
import net.minecraft.client.multiplayer.ClientLevel;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.tags.BlockTags;
|
|
import net.minecraft.util.Mth;
|
|
import net.minecraft.world.level.BlockGetter;
|
|
import net.minecraft.world.level.ClipContext;
|
|
import net.minecraft.world.level.block.Blocks;
|
|
import net.minecraft.world.level.block.state.BlockState;
|
|
import net.minecraft.world.level.material.MapColor;
|
|
import net.minecraft.world.phys.BlockHitResult;
|
|
import net.minecraft.world.phys.HitResult;
|
|
import net.minecraft.world.phys.Vec3;
|
|
|
|
public class GroundDustEffect {
|
|
private final ClientLevel level;
|
|
private final Vec3 center;
|
|
private final float maxRadius;
|
|
private final int particlesPerTick;
|
|
private final int maxAge;
|
|
private final float particleBaseSize;
|
|
private final Random random = new Random();
|
|
private final int raycastFrequency;
|
|
private Color currentDustColor = new Color(128, 128, 128);
|
|
private int age;
|
|
private boolean finished;
|
|
|
|
public GroundDustEffect(Vec3 position, float power) {
|
|
this.level = Minecraft.getInstance().level;
|
|
this.center = position;
|
|
float quality = Config.CLIENT.groundDustQuality.get().floatValue();
|
|
this.raycastFrequency = Math.max(1, Config.CLIENT.groundDustRaycastFrequency.get());
|
|
float powerFraction = Mth.clamp(power / 100.0f, 0.0f, 1.0f);
|
|
this.particlesPerTick = Math.max(1, (int)(Mth.lerp(powerFraction, 40.0f, 200.0f) * quality));
|
|
this.maxAge = Math.max(1, (int)(Mth.lerp(powerFraction, 30.0f, 70.0f) * quality));
|
|
this.maxRadius = power * this.calculateRadiusMultiplier(power);
|
|
this.particleBaseSize = Mth.lerp(powerFraction, 1.0f, 12.0f);
|
|
if (this.level == null || quality <= 0.0f) {
|
|
this.finished = true;
|
|
}
|
|
}
|
|
|
|
public void tick() {
|
|
if (this.finished || this.level == null) {
|
|
return;
|
|
}
|
|
if (!Config.CLIENT.enableGroundDustEffect.get()) {
|
|
this.finished = true;
|
|
return;
|
|
}
|
|
if (++this.age > this.maxAge) {
|
|
this.finished = true;
|
|
return;
|
|
}
|
|
|
|
float progress = this.age / (float)this.maxAge;
|
|
float easedProgress = 1.0f - (float)Math.pow(1.0f - progress, 3.0);
|
|
float currentRadius = this.maxRadius * easedProgress;
|
|
if (this.age % 10 == 0) {
|
|
double checkAngle = this.random.nextDouble() * Math.PI * 2.0;
|
|
double checkX = this.center.x + Math.cos(checkAngle) * currentRadius;
|
|
double checkZ = this.center.z + Math.sin(checkAngle) * currentRadius;
|
|
BlockHitResult hit = this.level.clip(new ClipContext(
|
|
new Vec3(checkX, this.center.y + 15.0, checkZ),
|
|
new Vec3(checkX, this.center.y - 15.0, checkZ),
|
|
ClipContext.Block.COLLIDER,
|
|
ClipContext.Fluid.NONE,
|
|
null));
|
|
if (hit.getType() == HitResult.Type.BLOCK) {
|
|
Color color = getDustColorForState(this.level.getBlockState(hit.getBlockPos()));
|
|
if (color != null) {
|
|
this.currentDustColor = color;
|
|
}
|
|
}
|
|
}
|
|
|
|
double cachedY = this.center.y;
|
|
for (int i = 0; i < this.particlesPerTick; ++i) {
|
|
double angle = i / (double)this.particlesPerTick * Math.PI * 2.0 + (this.random.nextDouble() - 0.5) * 0.1;
|
|
double radiusFrac = this.random.nextDouble();
|
|
double spawnRadius = currentRadius * (0.6 + radiusFrac * 0.4);
|
|
double x = this.center.x + Math.cos(angle) * spawnRadius;
|
|
double z = this.center.z + Math.sin(angle) * spawnRadius;
|
|
|
|
if (i % this.raycastFrequency == 0) {
|
|
BlockHitResult hit = this.level.clip(new ClipContext(
|
|
new Vec3(x, this.center.y + 15.0, z),
|
|
new Vec3(x, this.center.y - 15.0, z),
|
|
ClipContext.Block.COLLIDER,
|
|
ClipContext.Fluid.NONE,
|
|
null));
|
|
if (hit.getType() != HitResult.Type.BLOCK) {
|
|
continue;
|
|
}
|
|
cachedY = hit.getLocation().y;
|
|
}
|
|
|
|
double spawnY = cachedY;
|
|
Vec3 direction = new Vec3(x - this.center.x, 0.0, z - this.center.z).normalize();
|
|
double motionStrength = Mth.lerp(1.0f - progress, 0.05f, 0.45f);
|
|
double motionX = direction.x * motionStrength + (this.random.nextDouble() - 0.5) * 0.05;
|
|
double motionZ = direction.z * motionStrength + (this.random.nextDouble() - 0.5) * 0.05;
|
|
double motionY = (this.random.nextDouble() - 0.5) * 0.02;
|
|
Vec3 windDirection = ExplosionWindController.getWindDirection();
|
|
double windSpeed = ExplosionWindController.computeDustSpeed(0.0);
|
|
if (windDirection.lengthSqr() > 1.0E-4 && windSpeed > 0.0) {
|
|
motionX += windDirection.x * windSpeed * 0.65;
|
|
motionZ += windDirection.z * windSpeed * 0.65;
|
|
}
|
|
|
|
float red;
|
|
float green;
|
|
float blue;
|
|
float alpha;
|
|
float scale;
|
|
if (radiusFrac <= 0.2) {
|
|
red = 0.2f;
|
|
green = 0.2f;
|
|
blue = 0.2f;
|
|
alpha = 0.9f;
|
|
scale = this.particleBaseSize * 0.5f;
|
|
} else if (radiusFrac <= 0.65) {
|
|
red = 0.4f;
|
|
green = 0.4f;
|
|
blue = 0.4f;
|
|
alpha = 0.6f;
|
|
scale = this.particleBaseSize * 0.75f;
|
|
} else {
|
|
red = this.currentDustColor.getRed() / 255.0f;
|
|
green = this.currentDustColor.getGreen() / 255.0f;
|
|
blue = this.currentDustColor.getBlue() / 255.0f;
|
|
alpha = 0.35f;
|
|
scale = this.particleBaseSize;
|
|
}
|
|
|
|
SmokeParticleOptions options = new SmokeParticleOptions(
|
|
scale * (0.8f + this.random.nextFloat() * 0.4f),
|
|
100 + this.random.nextInt(60),
|
|
red,
|
|
green,
|
|
blue,
|
|
alpha,
|
|
false,
|
|
(float)windSpeed,
|
|
0.0f,
|
|
null);
|
|
this.level.addParticle(options, true, x, spawnY + 0.2, z, motionX, motionY, motionZ);
|
|
}
|
|
}
|
|
|
|
public boolean isFinished() {
|
|
return this.finished;
|
|
}
|
|
|
|
private Color getDustColorForState(BlockState state) {
|
|
if (state.is(BlockTags.WOOL) || state.getMapColor((BlockGetter)this.level, BlockPos.ZERO) == MapColor.NONE) {
|
|
return null;
|
|
}
|
|
if (state.is(Blocks.GRASS_BLOCK)) {
|
|
return new Color(Blocks.DIRT.defaultBlockState().getMapColor((BlockGetter)this.level, BlockPos.ZERO).col);
|
|
}
|
|
if (state.is(Blocks.STONE) || state.is(Blocks.COBBLESTONE)) {
|
|
return new Color(Blocks.COBBLESTONE.defaultBlockState().getMapColor((BlockGetter)this.level, BlockPos.ZERO).col);
|
|
}
|
|
return new Color(state.getMapColor((BlockGetter)this.level, BlockPos.ZERO).col);
|
|
}
|
|
|
|
private float calculateRadiusMultiplier(float power) {
|
|
if (power <= 5.0f) {
|
|
return 2.0f;
|
|
}
|
|
if (power <= 40.0f) {
|
|
return Mth.lerp((power - 5.0f) / 35.0f, 2.0f, 4.0f);
|
|
}
|
|
if (power <= 80.0f) {
|
|
return Mth.lerp((power - 40.0f) / 40.0f, 4.0f, 5.0f);
|
|
}
|
|
if (power <= 100.0f) {
|
|
return Mth.lerp((power - 80.0f) / 20.0f, 5.0f, 7.0f);
|
|
}
|
|
return 7.0f;
|
|
}
|
|
}
|