Restore cinematic explosion impact
All checks were successful
Build / build (push) Successful in 12m15s

This commit is contained in:
MrSphay
2026-05-09 17:50:33 +02:00
parent 77a55286b8
commit 55fde4c062
7 changed files with 255 additions and 63 deletions

View File

@@ -195,12 +195,12 @@ public class ServerExplosionHandler {
if (!((Boolean)Config.CLIENT.enableCameraShake.get()).booleanValue() && !((Boolean)Config.COMMON.enablePlayerShake.get()).booleanValue()) {
return new CameraShakeProfile(0.0f, 0, 0.0f);
}
double maxDistance = Math.max(18.0, power * (playerInCave ? 8.0 : 5.0));
double maxDistance = Math.max(22.0, power * (playerInCave ? 10.5 : 7.0));
double percent = Math.max(0.0, 1.0 - distance / maxDistance);
float amplifier = ((Double)Config.COMMON.playerShakeAmplifier.get()).floatValue();
float intensity = (float)Mth.clamp(percent * (0.45 + power * 0.035) * amplifier, 0.0, 4.0);
int duration = intensity <= 0.02f ? 0 : Mth.clamp((int)Math.round(10 + power * 1.4 + percent * 45.0), 6, 140);
float push = (float)Mth.clamp(percent * power * 0.07, 0.0, 2.0);
float intensity = (float)Mth.clamp(percent * (0.55 + power * 0.052) * amplifier, 0.0, 5.0);
int duration = intensity <= 0.02f ? 0 : Mth.clamp((int)Math.round(14 + power * 1.9 + percent * 58.0), 8, 190);
float push = (float)Mth.clamp(percent * power * 0.092, 0.0, 2.8);
return new CameraShakeProfile(intensity, duration, push);
}
@@ -209,8 +209,8 @@ public class ServerExplosionHandler {
if (direction.lengthSqr() < 0.0001) {
direction = new Vec3(0.0, 1.0, 0.0);
}
double strength = Mth.clamp((1.0 - distance / Math.max(12.0, power * 4.0)) * power * 0.06, 0.0, 1.4);
player.setDeltaMovement(player.getDeltaMovement().add(direction.normalize().scale(strength).add(0.0, Math.min(0.45, strength * 0.35), 0.0)));
double strength = Mth.clamp((1.0 - distance / Math.max(14.0, power * 5.0)) * power * 0.08, 0.0, 1.85);
player.setDeltaMovement(player.getDeltaMovement().add(direction.normalize().scale(strength).add(0.0, Math.min(0.58, strength * 0.38), 0.0)));
}
private static boolean hasLineOfSight(ServerLevel level, Vec3 from, Vec3 to) {

View File

@@ -23,6 +23,8 @@ public class ClientEffects {
private static final List<DelayedSound> TRACKED_SOUNDS = new ArrayList<>();
private static final List<DelayedShake> DELAYED_SHAKES = new ArrayList<>();
private static final List<PhysicsBasedExplosionEffect> EXPLOSION_EFFECTS = new ArrayList<>();
private static final List<ShockwaveEffect> SHOCKWAVE_EFFECTS = new ArrayList<>();
private static final List<LingeringFog> LINGERING_FOGS = new ArrayList<>();
private static int shakeTicks;
private static float shakeIntensity;
private static float pushIntensity;
@@ -71,7 +73,7 @@ public class ClientEffects {
if (!((Boolean)Config.CLIENT.enableFlashEffect.get()).booleanValue()) {
return;
}
flashTicks = Math.max(flashTicks, 8 + Mth.floor(power * 0.5f));
flashTicks = Math.max(flashTicks, Mth.clamp(9 + Mth.floor(power * 0.85f), 10, 42));
flashPower = Math.max(flashPower, power);
}
@@ -93,6 +95,25 @@ public class ClientEffects {
}
}
}
synchronized (SHOCKWAVE_EFFECTS) {
Iterator<ShockwaveEffect> iterator = SHOCKWAVE_EFFECTS.iterator();
while (iterator.hasNext()) {
ShockwaveEffect effect = iterator.next();
effect.tick();
if (effect.isFinished()) {
iterator.remove();
}
}
}
synchronized (LINGERING_FOGS) {
Iterator<LingeringFog> iterator = LINGERING_FOGS.iterator();
while (iterator.hasNext()) {
LingeringFog fog = iterator.next();
if (fog.tick(mc)) {
iterator.remove();
}
}
}
if (shakeTicks > 0 && mc.player != null) {
float fade = shakeTicks / Math.max(1.0f, shakeTicks + 8.0f);
float yaw = (mc.player.getRandom().nextFloat() - 0.5f) * shakeIntensity * 0.8f * fade;
@@ -122,8 +143,8 @@ public class ClientEffects {
return;
}
Minecraft mc = Minecraft.getInstance();
float alpha = Mth.clamp(flashTicks / 12.0f, 0.0f, 1.0f) * ((Double)Config.CLIENT.flashMaxOpacity.get()).floatValue();
alpha = Mth.clamp(alpha * (0.6f + flashPower * 0.018f), 0.0f, 0.92f);
float alpha = Mth.clamp(flashTicks / 18.0f, 0.0f, 1.0f) * ((Double)Config.CLIENT.flashMaxOpacity.get()).floatValue();
alpha = Mth.clamp(alpha * (0.7f + flashPower * 0.026f), 0.0f, 0.92f);
int color = ((int)(alpha * 255.0f) << 24) | 0xFFFFD7;
graphics.fill(0, 0, mc.getWindow().getGuiScaledWidth(), mc.getWindow().getGuiScaledHeight(), color);
}
@@ -133,11 +154,8 @@ public class ClientEffects {
if (mc.level == null || !((Boolean)Config.CLIENT.enableShockwaveEffect.get()).booleanValue()) {
return;
}
int count = Math.min(120, Math.max(24, Math.round(power * 5.0f)));
for (int i = 0; i < count; ++i) {
double angle = Math.PI * 2.0 * i / count;
double speed = 0.18 + Math.min(0.75, power * 0.018);
mc.level.addParticle(ModParticles.LINE_SPARK.get(), position.x, position.y + 0.12, position.z, Math.cos(angle) * speed, 0.01, Math.sin(angle) * speed);
synchronized (SHOCKWAVE_EFFECTS) {
SHOCKWAVE_EFFECTS.add(new ShockwaveEffect(position, power));
}
}
@@ -146,11 +164,13 @@ public class ClientEffects {
if (mc.level == null || !((Boolean)Config.CLIENT.enableGroundDustEffect.get()).booleanValue()) {
return;
}
int count = Math.min(180, Math.max(30, Math.round(power * 8.0f * ((Double)Config.CLIENT.groundDustQuality.get()).floatValue())));
mc.level.addParticle(new SmokeParticleOptions(Math.max(1.4f, power * 0.35f), 80, 0.2f, 0.17f, 0.14f, 0.68f, true, 0.0f, 0.2f, null), position.x, position.y + 0.2, position.z, 0.0, 0.04, 0.0);
float quality = ((Double)Config.CLIENT.groundDustQuality.get()).floatValue();
int count = Math.min(260, Math.max(36, Math.round(power * 9.5f * quality)));
float coreScale = Mth.clamp(Math.max(1.6f, power * 0.42f), 1.6f, 10.5f);
mc.level.addParticle(new SmokeParticleOptions(coreScale, 110, 0.2f, 0.17f, 0.14f, 0.64f, true, 0.0f, 0.2f, null), position.x, position.y + 0.2, position.z, 0.0, 0.045, 0.0);
for (int i = 0; i < count; ++i) {
Vec3 velocity = randomHorizontal(mc.player == null ? 0 : mc.player.getRandom().nextLong()).scale(0.04 + mc.level.random.nextDouble() * 0.16);
mc.level.addParticle(new SmokeParticleOptions(0.9f + mc.level.random.nextFloat() * 1.7f, 45 + mc.level.random.nextInt(55), 0.18f, 0.16f, 0.13f, 0.58f, true, 0.0f, 0.2f, null), position.x, position.y + 0.1, position.z, velocity.x, 0.03 + mc.level.random.nextDouble() * 0.05, velocity.z);
Vec3 velocity = randomHorizontal(mc.level.random.nextLong()).scale(0.04 + mc.level.random.nextDouble() * 0.16);
mc.level.addParticle(new SmokeParticleOptions(1.0f + mc.level.random.nextFloat() * 2.1f, 58 + mc.level.random.nextInt(62), 0.18f, 0.16f, 0.13f, 0.52f, true, 0.0f, 0.2f, null), position.x, position.y + 0.1, position.z, velocity.x, 0.025 + mc.level.random.nextDouble() * 0.05, velocity.z);
}
}
@@ -159,11 +179,14 @@ public class ClientEffects {
if (mc.level == null || !((Boolean)Config.CLIENT.enableGroundMistEffect.get()).booleanValue()) {
return;
}
int count = Math.min(120, Math.max(20, Math.round(power * 5.0f * ((Double)Config.CLIENT.groundMistQuality.get()).floatValue())));
int count = Math.min(160, Math.max(24, Math.round(power * 6.0f * ((Double)Config.CLIENT.groundMistQuality.get()).floatValue())));
for (int i = 0; i < count; ++i) {
Vec3 velocity = randomHorizontal(mc.level.random.nextLong()).scale(0.025 + mc.level.random.nextDouble() * 0.11);
mc.level.addParticle(new SmokeParticleOptions(1.2f + mc.level.random.nextFloat() * 2.2f, 65 + mc.level.random.nextInt(60), 0.32f, 0.31f, 0.29f, 0.34f, false, 0.0f, 0.1f, null), position.x, position.y + 0.08, position.z, velocity.x, 0.01, velocity.z);
}
synchronized (LINGERING_FOGS) {
LINGERING_FOGS.add(new LingeringFog(position, power));
}
}
public static void triggerLineSparks(Vec3 position, float power) {
@@ -198,6 +221,50 @@ public class ClientEffects {
return new Vec3(Math.cos(angle), 0.0, Math.sin(angle));
}
private static final class LingeringFog {
private final Vec3 position;
private final float power;
private final int lifetime;
private final float radius;
private int age;
private LingeringFog(Vec3 position, float power) {
this.position = position;
this.power = power;
this.lifetime = Mth.clamp(80 + Math.round(power * 4.0f), 90, 260);
this.radius = Mth.clamp(5.0f + power * 1.8f, 7.0f, 72.0f);
}
private boolean tick(Minecraft mc) {
if (mc.level == null) {
return true;
}
if (++this.age >= this.lifetime) {
return true;
}
if (!((Boolean)Config.CLIENT.enableGroundMistEffect.get()).booleanValue() && !((Boolean)Config.CLIENT.enableGroundDustEffect.get()).booleanValue()) {
return false;
}
if (this.age % 2 != 0) {
return false;
}
float progress = this.age / (float)this.lifetime;
float fade = Mth.clamp(1.0f - progress, 0.0f, 1.0f);
int count = Mth.clamp(Math.round(this.power * 0.26f * fade), 1, 10);
for (int i = 0; i < count; ++i) {
double angle = mc.level.random.nextDouble() * Math.PI * 2.0;
double distance = this.radius * (0.18 + mc.level.random.nextDouble() * (0.82 + progress * 0.35));
double x = this.position.x + Math.cos(angle) * distance;
double z = this.position.z + Math.sin(angle) * distance;
double y = this.position.y + 0.04 + mc.level.random.nextDouble() * 0.55;
float scale = Mth.clamp(1.1f + this.power * 0.075f + mc.level.random.nextFloat() * 1.6f, 1.0f, 4.8f);
float alpha = Mth.clamp(0.30f * fade, 0.03f, 0.30f);
mc.level.addParticle(new SmokeParticleOptions(scale, 80 + mc.level.random.nextInt(70), 0.29f, 0.28f, 0.26f, alpha, false, 0.0f, 0.04f, null), x, y, z, Math.cos(angle) * 0.018, 0.004, Math.sin(angle) * 0.018);
}
return false;
}
}
private static final class DelayedSound {
private final PlayTrackedSoundPacket packet;
private long delayTicks;

View File

@@ -25,9 +25,11 @@ public class ConcussionAudioEffect {
return;
}
float chance = ((Double)Config.CLIENT.concussionChanceMultiplier.get()).floatValue();
currentIntensity = Math.max(currentIntensity, (float)(computeBaseIntensityPercent(effectivePercent) / 100.0 * chance));
ticksRemaining = Math.max(ticksRemaining, (int)Math.round((computeBaseSilentSeconds(effectivePercent, explosionInCave) + power * 0.08) * 20.0 * ((Double)Config.CLIENT.concussionDurationMultiplier.get()).floatValue()));
ticksRemaining = Math.min(ticksRemaining, 20 * 18);
float powerBoost = (float)Math.min(1.55, 0.76 + power / 34.0);
currentIntensity = Math.max(currentIntensity, (float)(computeBaseIntensityPercent(effectivePercent) / 100.0 * chance * powerBoost));
currentIntensity = Math.min(currentIntensity, explosionInCave ? 1.35f : 1.15f);
ticksRemaining = Math.max(ticksRemaining, (int)Math.round((computeBaseSilentSeconds(effectivePercent, explosionInCave) + power * 0.13) * 20.0 * ((Double)Config.CLIENT.concussionDurationMultiplier.get()).floatValue()));
ticksRemaining = Math.min(ticksRemaining, 20 * 24);
if (((Boolean)Config.CLIENT.enableCameraSway.get()).booleanValue()) {
CameraShakeConcussionEffect.start(Math.max(1, ticksRemaining / 20), currentIntensity * ((Double)Config.CLIENT.cameraSwayIntensity.get()).floatValue());
}
@@ -59,7 +61,7 @@ public class ConcussionAudioEffect {
updateHeartbeat(mc.player, currentIntensity);
}
if (tinnitusCooldown > 0 && --tinnitusCooldown == 0) {
mc.level.playLocalSound(mc.player.getX(), mc.player.getY(), mc.player.getZ(), ModSounds.LOW_SOUND.get(), SoundSource.AMBIENT, Math.min(0.8f, currentIntensity), 1.25f, false);
mc.level.playLocalSound(mc.player.getX(), mc.player.getY(), mc.player.getZ(), ModSounds.LOW_SOUND.get(), SoundSource.AMBIENT, Math.min(1.0f, 0.18f + currentIntensity), 1.18f, false);
}
}
@@ -68,10 +70,10 @@ public class ConcussionAudioEffect {
if (mc.level == null || heartbeatTicks-- > 0) {
return;
}
heartbeatTicks = Math.max(10, (int)(32 - currentIntensity * 16.0f));
mc.level.playLocalSound(player.getX(), player.getY(), player.getZ(), ModSounds.HEART_LAB.get(), SoundSource.PLAYERS, 0.28f + currentIntensity * 0.35f, 1.0f, false);
heartbeatTicks = Math.max(7, (int)(30 - currentIntensity * 18.0f));
mc.level.playLocalSound(player.getX(), player.getY(), player.getZ(), ModSounds.HEART_LAB.get(), SoundSource.PLAYERS, 0.3f + currentIntensity * 0.48f, 0.96f + currentIntensity * 0.05f, false);
if (heartbeatTicks > 4) {
mc.level.playLocalSound(player.getX(), player.getY(), player.getZ(), ModSounds.HEART_DAB.get(), SoundSource.PLAYERS, 0.22f + currentIntensity * 0.25f, 1.0f, false);
mc.level.playLocalSound(player.getX(), player.getY(), player.getZ(), ModSounds.HEART_DAB.get(), SoundSource.PLAYERS, 0.24f + currentIntensity * 0.34f, 0.98f + currentIntensity * 0.05f, false);
}
}
@@ -103,15 +105,15 @@ public class ConcussionAudioEffect {
}
public static double computeMaxDistance(float power, boolean explosionInCave) {
return explosionInCave ? Math.max(18.0, power * 8.0) : Math.max(10.0, power * 5.0);
return explosionInCave ? Math.max(24.0, power * 11.0) : Math.max(16.0, power * 7.5);
}
public static double applyOcclusion(double percent) {
return Math.max(0.0, percent * 0.5);
return Math.max(0.0, percent * 0.62);
}
public static double computeBaseSilentSeconds(double effectivePercent, boolean explosionInCave) {
return Math.max(0.0, effectivePercent / (explosionInCave ? 16.0 : 24.0));
return Math.max(0.0, effectivePercent / (explosionInCave ? 13.5 : 19.0));
}
public static double computeBaseIntensityPercent(double effectivePercent) {

View File

@@ -16,7 +16,7 @@ public class DeafnessConcussionEffect {
DeafnessConcussionEffect.intensity = Math.max(DeafnessConcussionEffect.intensity, intensity);
totalTicks = Math.max(1, (int)Math.round(Math.max(1.0, silentSeconds) * 20.0));
ticksRemaining = Math.max(ticksRemaining, totalTicks);
LowPassConcussionEffect.setDeafnessGain((float)Math.max(0.18, 1.0 - intensity * 0.75));
LowPassConcussionEffect.setDeafnessGain((float)Math.max(0.12, 1.0 - intensity * 0.82));
return true;
}
@@ -44,7 +44,7 @@ public class DeafnessConcussionEffect {
}
--ticksRemaining;
double remaining = ticksRemaining / Math.max(1.0, totalTicks);
LowPassConcussionEffect.setDeafnessGain((float)Math.max(0.18, lerp(1.0, 1.0 - intensity * 0.75, easeOutQuad(remaining))));
LowPassConcussionEffect.setDeafnessGain((float)Math.max(0.12, lerp(1.0, 1.0 - intensity * 0.82, easeOutQuad(remaining))));
}
public static double lerp(double a, double b, double t) {

View File

@@ -90,7 +90,7 @@ public class LowPassConcussionEffect {
double remaining = ticksRemaining / Math.max(1.0, totalTicks);
double curve = easeOutQuad(Math.max(0.0, Math.min(1.0, remaining)));
float amount = (float)(targetIntensity * curve);
currentHfMultiplier = lerp(1.0f, compatibilityMode ? 0.45f : 0.18f, amount);
currentGainMultiplier = lerp(1.0f, 0.55f, amount);
currentHfMultiplier = lerp(1.0f, compatibilityMode ? 0.38f : 0.12f, Math.min(1.0f, amount));
currentGainMultiplier = lerp(1.0f, 0.46f, Math.min(1.0f, amount));
}
}

View File

@@ -14,12 +14,18 @@ public class PhysicsBasedExplosionEffect {
private final Vec3 position;
private final float power;
private final int lifetime;
private final float stemHeight;
private final float capRadius;
private final float stemRadius;
private int age;
public PhysicsBasedExplosionEffect(Vec3 position, float power) {
this.position = position;
this.power = power;
this.lifetime = Mth.clamp(18 + Math.round(power * 1.4f), 22, 90);
this.lifetime = Mth.clamp(64 + Math.round(power * 4.2f), 78, 210);
this.stemHeight = Mth.clamp(3.6f + power * 0.42f, 4.5f, 28.0f);
this.capRadius = Mth.clamp(3.0f + power * 0.46f, 4.0f, 26.0f);
this.stemRadius = Mth.clamp(0.75f + power * 0.055f, 0.9f, 4.0f);
this.spawnInitialBurst();
}
@@ -30,19 +36,17 @@ public class PhysicsBasedExplosionEffect {
return;
}
float progress = this.age / (float)this.lifetime;
if (progress < 0.45f) {
int count = Math.max(2, Math.round(this.power * 0.7f));
for (int i = 0; i < count; ++i) {
Vec3 velocity = randomDirection(level).scale(0.05 + level.random.nextDouble() * 0.18);
level.addParticle(new CustomGlowParticleOptions(i % 2, this.power, 0.75f + level.random.nextFloat() * 0.75f, i % 3, (float)this.position.y, this.power * 2.2f, progress), this.position.x, this.position.y, this.position.z, velocity.x, Math.abs(velocity.y) * 0.45, velocity.z);
}
if (progress < 0.62f) {
this.spawnRisingStem(level, progress);
}
if (progress < 0.8f && ((Boolean)Config.CLIENT.enablePlasmaParticles.get()).booleanValue()) {
int count = Math.max(1, Math.round(this.power * 0.28f));
for (int i = 0; i < count; ++i) {
Vec3 velocity = randomDirection(level).scale(0.18 + level.random.nextDouble() * 0.7);
level.addParticle(new PlasmaParticleOptions(this.power), this.position.x, this.position.y, this.position.z, velocity.x, velocity.y, velocity.z);
}
if (progress > 0.06f && progress < 0.86f) {
this.spawnMushroomCap(level, progress);
}
if (progress < 0.58f && ((Boolean)Config.CLIENT.enablePlasmaParticles.get()).booleanValue()) {
this.spawnPlasmaCore(level, progress);
}
if (progress > 0.34f && progress < 0.94f) {
this.spawnTrailingSmoke(level, progress);
}
}
@@ -55,33 +59,107 @@ public class PhysicsBasedExplosionEffect {
if (level == null) {
return;
}
Config.Client.ParticleRenderMode mode = Config.CLIENT.particleRenderMode.get();
int glowCount = switch (mode) {
case REALISTIC -> Math.round(this.power * 10.0f);
case REALISTIC_2 -> Math.round(this.power * 12.0f);
case VANILA -> Math.round(this.power * 6.0f);
};
glowCount = Mth.clamp(glowCount, 24, 260);
float modeScale = modeScale();
int glowCount = Mth.clamp(Math.round(this.power * 9.0f * modeScale), 28, 220);
for (int i = 0; i < glowCount; ++i) {
Vec3 velocity = randomDirection(level).scale(0.04 + level.random.nextDouble() * 0.22);
level.addParticle(new CustomGlowParticleOptions(i % 2, this.power, 0.75f + level.random.nextFloat() * 0.9f, i % 3, (float)this.position.y, this.power * 2.2f, 0.0f), this.position.x, this.position.y, this.position.z, velocity.x, velocity.y * 0.35, velocity.z);
Vec3 velocity = randomDirection(level).scale(0.08 + level.random.nextDouble() * 0.42);
level.addParticle(new CustomGlowParticleOptions(i % 2, this.power, 0.8f + level.random.nextFloat() * 0.9f, i % 3, (float)this.position.y, this.capRadius, 0.0f), this.position.x, this.position.y + 0.2, this.position.z, velocity.x, Math.abs(velocity.y) * 0.45 + 0.04, velocity.z);
}
int smokeCount = Mth.clamp(Math.round(this.power * 7.0f), 18, 180);
int smokeCount = Mth.clamp(Math.round(this.power * 5.5f * modeScale), 26, 150);
for (int i = 0; i < smokeCount; ++i) {
Vec3 velocity = randomDirection(level).scale(0.02 + level.random.nextDouble() * 0.12);
level.addParticle(new SmokeParticleOptions(0.8f + level.random.nextFloat() * Math.max(1.6f, this.power * 0.28f), 60 + level.random.nextInt(60), 0.18f, 0.16f, 0.13f, 0.62f, true, 0.0f, 0.2f, null), this.position.x, this.position.y + 0.1, this.position.z, velocity.x, Math.abs(velocity.y) * 0.25 + 0.02, velocity.z);
Vec3 velocity = randomDirection(level).scale(0.03 + level.random.nextDouble() * 0.18);
float scale = 1.0f + level.random.nextFloat() * Math.max(1.8f, this.power * 0.22f);
level.addParticle(new SmokeParticleOptions(scale, 70 + level.random.nextInt(65), 0.22f, 0.19f, 0.15f, 0.64f, true, 0.0f, 0.12f, null), this.position.x, this.position.y + 0.15, this.position.z, velocity.x, Math.abs(velocity.y) * 0.22 + 0.03, velocity.z);
}
int sparks = Mth.clamp(Math.round(this.power * 5.0f), 10, 140);
int sparks = Mth.clamp(Math.round(this.power * 4.2f * modeScale), 12, 120);
for (int i = 0; i < sparks; ++i) {
Vec3 velocity = randomDirection(level).scale(0.28 + level.random.nextDouble() * 1.1);
level.addParticle(ModParticles.LINE_SPARK.get(), this.position.x, this.position.y + 0.15, this.position.z, velocity.x, Math.abs(velocity.y) * 0.5, velocity.z);
Vec3 velocity = randomDirection(level).scale(0.45 + level.random.nextDouble() * 1.35);
level.addParticle(ModParticles.LINE_SPARK.get(), this.position.x, this.position.y + 0.25, this.position.z, velocity.x, Math.abs(velocity.y) * 0.52, velocity.z);
}
}
private void spawnRisingStem(ClientLevel level, float progress) {
float modeScale = modeScale();
int count = Mth.clamp(Math.round(this.power * 0.28f * modeScale), 2, 10);
float lift = this.stemHeight * Mth.clamp(progress / 0.62f, 0.0f, 1.0f);
for (int i = 0; i < count; ++i) {
double angle = level.random.nextDouble() * Math.PI * 2.0;
double radius = this.stemRadius * Math.sqrt(level.random.nextDouble());
double x = this.position.x + Math.cos(angle) * radius;
double z = this.position.z + Math.sin(angle) * radius;
double y = this.position.y + 0.4 + level.random.nextDouble() * Math.max(1.4, lift);
float fade = 1.0f - progress * 0.45f;
float scale = Mth.clamp(1.3f + this.power * 0.16f + level.random.nextFloat() * 1.4f, 1.2f, 7.2f);
level.addParticle(new SmokeParticleOptions(scale, 92 + level.random.nextInt(76), 0.17f, 0.15f, 0.13f, 0.58f * fade, true, 0.0f, progress, null), x, y, z, Math.cos(angle) * 0.025, 0.075 + level.random.nextDouble() * 0.065, Math.sin(angle) * 0.025);
}
}
private void spawnMushroomCap(ClientLevel level, float progress) {
float capProgress = Mth.clamp((progress - 0.06f) / 0.58f, 0.0f, 1.0f);
float spread = this.capRadius * easeOutCubic(capProgress);
float capY = (float)this.position.y + this.stemHeight * (0.72f + capProgress * 0.28f);
int count = Mth.clamp(Math.round(this.power * 0.34f * modeScale()), 2, 14);
for (int i = 0; i < count; ++i) {
double angle = level.random.nextDouble() * Math.PI * 2.0;
double radius = spread * (0.35 + level.random.nextDouble() * 0.78);
double x = this.position.x + Math.cos(angle) * radius;
double z = this.position.z + Math.sin(angle) * radius;
double y = capY + (level.random.nextDouble() - 0.35) * Math.max(1.0, this.stemHeight * 0.18);
float alpha = Mth.clamp(0.64f * (1.0f - progress * 0.55f), 0.16f, 0.64f);
float scale = Mth.clamp(1.6f + this.power * 0.18f + level.random.nextFloat() * 2.0f, 1.4f, 8.4f);
Vec3 outward = new Vec3(x - this.position.x, 0.0, z - this.position.z);
if (outward.lengthSqr() < 0.0001) {
outward = new Vec3(Math.cos(angle), 0.0, Math.sin(angle));
}
Vec3 velocity = outward.normalize().scale(0.035 + capProgress * 0.055).add(0.0, 0.02 + level.random.nextDouble() * 0.035, 0.0);
level.addParticle(new SmokeParticleOptions(scale, 100 + level.random.nextInt(92), 0.18f, 0.16f, 0.14f, alpha, true, 0.0f, capProgress, null), x, y, z, velocity.x, velocity.y, velocity.z);
}
}
private void spawnPlasmaCore(ClientLevel level, float progress) {
int count = Mth.clamp(Math.round(this.power * 0.16f * modeScale()), 1, 8);
for (int i = 0; i < count; ++i) {
Vec3 velocity = randomDirection(level).scale(0.18 + level.random.nextDouble() * 0.78);
double y = this.position.y + 0.25 + level.random.nextDouble() * this.stemHeight * Mth.clamp(progress * 1.6f, 0.12f, 1.0f);
level.addParticle(new PlasmaParticleOptions(this.power), this.position.x, y, this.position.z, velocity.x, Math.abs(velocity.y) * 0.45, velocity.z);
}
}
private void spawnTrailingSmoke(ClientLevel level, float progress) {
if (!((Boolean)Config.CLIENT.enableGroundMistEffect.get()).booleanValue()) {
return;
}
float fade = 1.0f - progress;
int count = Mth.clamp(Math.round(this.power * 0.14f * modeScale()), 1, 6);
for (int i = 0; i < count; ++i) {
double angle = level.random.nextDouble() * Math.PI * 2.0;
double radius = this.capRadius * (0.15 + level.random.nextDouble() * 0.95);
double x = this.position.x + Math.cos(angle) * radius;
double z = this.position.z + Math.sin(angle) * radius;
double y = this.position.y + 0.1 + level.random.nextDouble() * 1.2;
float scale = Mth.clamp(1.0f + this.power * 0.1f + level.random.nextFloat() * 1.7f, 1.0f, 5.8f);
level.addParticle(new SmokeParticleOptions(scale, 84 + level.random.nextInt(70), 0.26f, 0.25f, 0.23f, 0.28f * fade, false, 0.0f, 0.05f, null), x, y, z, Math.cos(angle) * 0.025, 0.006, Math.sin(angle) * 0.025);
}
}
private static Vec3 randomDirection(ClientLevel level) {
double yaw = level.random.nextDouble() * Math.PI * 2.0;
double y = level.random.nextDouble() * 0.9 - 0.25;
double y = level.random.nextDouble() * 1.15 - 0.25;
double horizontal = Math.sqrt(Math.max(0.0, 1.0 - y * y));
return new Vec3(Math.cos(yaw) * horizontal, y, Math.sin(yaw) * horizontal);
}
private static float modeScale() {
return switch (Config.CLIENT.particleRenderMode.get()) {
case REALISTIC -> 1.0f;
case REALISTIC_2 -> 1.12f;
case VANILA -> 0.68f;
};
}
private static float easeOutCubic(float t) {
float clamped = Mth.clamp(t, 0.0f, 1.0f);
float inv = 1.0f - clamped;
return 1.0f - inv * inv * inv;
}
}

View File

@@ -1,15 +1,60 @@
package com.vinlanx.explosionoverhaul.client;
import com.vinlanx.explosionoverhaul.Config;
import com.vinlanx.explosionoverhaul.ModParticles;
import com.vinlanx.explosionoverhaul.SmokeParticleOptions;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.util.Mth;
import net.minecraft.world.phys.Vec3;
public class ShockwaveEffect {
private final Vec3 position;
private final float power;
private final int lifetime;
private final float maxRadius;
private int age;
public ShockwaveEffect(Vec3 position, float power) {
this.position = position;
this.power = power;
this.lifetime = Mth.clamp(18 + Math.round(power * 0.9f), 24, 72);
this.maxRadius = Mth.clamp(8.0f + power * 2.9f, 10.0f, 96.0f);
}
public void tick() {
++this.age;
ClientLevel level = Minecraft.getInstance().level;
if (level == null || !((Boolean)Config.CLIENT.enableShockwaveEffect.get()).booleanValue()) {
return;
}
float progress = this.age / (float)this.lifetime;
float radius = this.maxRadius * easeOutCubic(progress);
float fade = Mth.clamp(1.0f - progress, 0.0f, 1.0f);
int points = Mth.clamp(Math.round(8.0f + this.power * 1.15f), 12, 44);
for (int i = 0; i < points; ++i) {
double angle = (Math.PI * 2.0 * i / points) + level.random.nextDouble() * 0.22;
double x = this.position.x + Math.cos(angle) * radius;
double z = this.position.z + Math.sin(angle) * radius;
double y = this.position.y + 0.08 + level.random.nextDouble() * 0.35;
double outwardSpeed = 0.18 + Math.min(0.9, this.power * 0.025);
if (progress < 0.72f) {
level.addParticle(ModParticles.LINE_SPARK.get(), x, y + 0.16, z, Math.cos(angle) * outwardSpeed, 0.015 + level.random.nextDouble() * 0.04, Math.sin(angle) * outwardSpeed);
}
if (((Boolean)Config.CLIENT.enableGroundDustEffect.get()).booleanValue()) {
float scale = Mth.clamp(0.8f + this.power * 0.055f + level.random.nextFloat() * 0.8f, 0.8f, 4.2f);
level.addParticle(new SmokeParticleOptions(scale, 42 + level.random.nextInt(36), 0.28f, 0.25f, 0.21f, 0.34f * fade, true, 0.0f, 0.05f, null), x, y, z, Math.cos(angle) * 0.055, 0.012, Math.sin(angle) * 0.055);
}
}
}
public boolean isFinished() {
return true;
return this.age >= this.lifetime;
}
private static float easeOutCubic(float t) {
float clamped = Mth.clamp(t, 0.0f, 1.0f);
float inv = 1.0f - clamped;
return 1.0f - inv * inv * inv;
}
}