/* * Decompiled with CFR 0.152. */ package com.vinlanx.explosionoverhaul.client; import com.mojang.blaze3d.systems.RenderSystem; import com.vinlanx.explosionoverhaul.Config; import com.vinlanx.explosionoverhaul.ModParticles; import com.vinlanx.explosionoverhaul.PlayTrackedSoundPacket; import com.vinlanx.explosionoverhaul.client.Blur; import com.vinlanx.explosionoverhaul.client.CameraShakeConcussionEffect; import com.vinlanx.explosionoverhaul.client.ExplosionWindController; import com.vinlanx.explosionoverhaul.client.GroundDustEffect; import com.vinlanx.explosionoverhaul.client.GroundMistEffect; import com.vinlanx.explosionoverhaul.client.PhysicsBasedExplosionEffect; import com.vinlanx.explosionoverhaul.client.PositionalSoundInstance; import com.vinlanx.explosionoverhaul.client.ShockwaveEffect; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Random; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.player.LocalPlayer; import net.minecraft.client.resources.sounds.SoundInstance; import net.minecraft.client.sounds.SoundManager; import net.minecraft.core.BlockPos; import net.minecraft.core.particles.BlockParticleOption; import net.minecraft.core.particles.ParticleOptions; import net.minecraft.core.particles.ParticleTypes; import net.minecraft.core.particles.SimpleParticleType; import net.minecraft.resources.ResourceLocation; import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundSource; import net.minecraft.util.Mth; import net.minecraft.util.RandomSource; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; 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.phys.BlockHitResult; import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.Vec3; import net.minecraftforge.client.event.RenderGuiOverlayEvent; import net.minecraftforge.registries.ForgeRegistries; public class ClientEffects { private static float currentShakeIntensity = 0.0f; private static int shakeDurationTicks = 0; private static float currentPushIntensity = 0.0f; private static float lastYawOffset = 0.0f; private static float lastPitchOffset = 0.0f; private static final Random random = new Random(); private static final List activeExplosions = new ArrayList(); private static final List activeTrackedSounds = new ArrayList(); private static final List activeShockwaves = new ArrayList(); private static final List activeDustClouds = new ArrayList(); private static final List activeMistClouds = new ArrayList(); private static final List activeFlashEffects = new ArrayList(); private static final List pendingShakes = new ArrayList(); public static void addTrackedSound(PlayTrackedSoundPacket msg) { SoundEvent sound = (SoundEvent)ForgeRegistries.SOUND_EVENTS.getValue(msg.getSoundId()); if (sound != null) { activeTrackedSounds.add(new TrackedSound(msg.getExplosionPos(), sound, msg.getVolume(), msg.getPitch(), msg.getDelayTicks(), msg.isPlayerInHouse())); } } private static Vec3 calculateSoundPosition(Player player, Vec3 explosionPos, boolean isPlayerInHouse) { float FIXED_DISTANCE = 45.0f; Vec3 playerPos = player.m_146892_(); Vec3 startPos = isPlayerInHouse ? explosionPos : playerPos; Vec3 endPos = isPlayerInHouse ? playerPos : explosionPos; ClipContext context = new ClipContext(startPos, endPos, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, (Entity)player); BlockHitResult hitResult = player.m_9236_().m_45547_(context); if (hitResult.m_6662_() == HitResult.Type.MISS) { Vec3 direction = explosionPos.m_82546_(playerPos).m_82541_(); if (direction.m_82556_() < 0.001) { direction = player.m_20154_(); } return playerPos.m_82549_(direction.m_82490_(45.0)); } Vec3 hitPos = hitResult.m_82450_(); Vec3 rayDir = endPos.m_82546_(startPos).m_82541_(); return hitPos.m_82546_(rayDir.m_82490_(0.1)); } private static void handleTrackedSoundsTick() { Minecraft mc = Minecraft.m_91087_(); if (mc.f_91074_ == null || mc.m_91106_() == null) { return; } Iterator iterator = activeTrackedSounds.iterator(); while (iterator.hasNext()) { TrackedSound tracked = iterator.next(); if (tracked.isFinished()) { iterator.remove(); continue; } tracked.tick((Player)mc.f_91074_, mc.m_91106_(), mc.f_91074_.m_217043_()); } } public static void triggerLocalCameraShake(float intensity, int durationTicks, float pushIntensity) { if (!((Boolean)Config.CLIENT.enableCameraShake.get()).booleanValue()) { return; } float amplifiedIntensity = intensity * (((Double)Config.CLIENT.cameraShakeAmplifier.get()).floatValue() * 10.0f); float amplifiedPush = 0.0f; if (((Boolean)Config.COMMON.enablePlayerShake.get()).booleanValue()) { amplifiedPush = pushIntensity * (((Double)Config.COMMON.playerShakeAmplifier.get()).floatValue() * 5.0f); } if (amplifiedIntensity > currentShakeIntensity || shakeDurationTicks == 0 || durationTicks > shakeDurationTicks) { currentShakeIntensity = amplifiedIntensity; shakeDurationTicks = durationTicks; currentPushIntensity = amplifiedPush; } } public static void triggerDelayedCameraShake(float intensity, int durationTicks, float pushIntensity, int delayTicks) { if (!((Boolean)Config.CLIENT.enableCameraShake.get()).booleanValue()) { return; } if (delayTicks <= 0) { ClientEffects.triggerLocalCameraShake(intensity, durationTicks, pushIntensity); return; } pendingShakes.add(new PendingShake(delayTicks, intensity, durationTicks, pushIntensity)); } public static void triggerRealisticExplosion(Vec3 position, float power) { activeExplosions.add(new PhysicsBasedExplosionEffect(position, power)); } public static void addFlashEffect(Vec3 explosionPos, float power) { activeFlashEffects.add(new FlashEffect(explosionPos, power)); } public static void onClientTick() { if (Minecraft.m_91087_().m_91104_()) { return; } Blur.onClientTick(); CameraShakeConcussionEffect.onClientTick(); ExplosionWindController.tick(); ClientEffects.handleCameraShakeTick(); ClientEffects.handlePendingShakesTick(); ClientEffects.handleTrackedSoundsTick(); activeExplosions.removeIf(effect -> { effect.tick(); return effect.isFinished(); }); activeShockwaves.removeIf(effect -> { effect.tick(); return effect.isFinished(); }); activeDustClouds.removeIf(effect -> { effect.tick(); return effect.isFinished(); }); activeMistClouds.removeIf(effect -> { effect.tick(); return effect.isFinished(); }); activeFlashEffects.removeIf(effect -> effect.isFinished()); } public static void renderFlash(RenderGuiOverlayEvent.Post event) { if (!((Boolean)Config.CLIENT.enableFlashEffect.get()).booleanValue()) { return; } Minecraft mc = Minecraft.m_91087_(); if (mc.f_91074_ == null || activeFlashEffects.isEmpty()) { return; } float maxOpacity = 0.0f; for (FlashEffect effect : activeFlashEffects) { float opacity = effect.getCurrentOpacity((Player)mc.f_91074_); if (!(opacity > maxOpacity)) continue; maxOpacity = opacity; } if (maxOpacity <= 0.0f) { return; } GuiGraphics guiGraphics = event.getGuiGraphics(); int screenWidth = mc.m_91268_().m_85445_(); int screenHeight = mc.m_91268_().m_85446_(); ResourceLocation flashTexture = ResourceLocation.fromNamespaceAndPath((String)"explosionoverhaul", (String)"textures/effects/flash.png"); RenderSystem.enableBlend(); RenderSystem.defaultBlendFunc(); RenderSystem.setShaderColor((float)1.0f, (float)1.0f, (float)1.0f, (float)maxOpacity); guiGraphics.m_280163_(flashTexture, 0, 0, 0.0f, 0.0f, screenWidth, screenHeight, screenWidth, screenHeight); RenderSystem.disableBlend(); RenderSystem.setShaderColor((float)1.0f, (float)1.0f, (float)1.0f, (float)1.0f); } private static void handlePendingShakesTick() { if (pendingShakes.isEmpty()) { return; } Iterator it = pendingShakes.iterator(); while (it.hasNext()) { PendingShake ps = it.next(); --ps.delayTicks; if (ps.delayTicks > 0) continue; ClientEffects.triggerLocalCameraShake(ps.intensity, ps.durationTicks, ps.pushIntensity); it.remove(); } } public static void triggerShockwave(Vec3 position, float power) { activeShockwaves.add(new ShockwaveEffect(position, power)); } public static void triggerDustCloud(Vec3 position, float power) { if (!((Boolean)Config.CLIENT.enableGroundDustEffect.get()).booleanValue()) { return; } activeDustClouds.add(new GroundDustEffect(position, power)); } public static void triggerMistCloud(Vec3 position, float power) { if (!((Boolean)Config.CLIENT.enableGroundMistEffect.get()).booleanValue()) { return; } activeMistClouds.add(new GroundMistEffect(position, power)); } public static void triggerAmbientCaveDust(float power) { int i; Minecraft mc = Minecraft.m_91087_(); LocalPlayer player = mc.f_91074_; ClientLevel level = mc.f_91073_; if (player == null || level == null) { return; } int particleCount = 15 + (int)((double)(power / 10.0f) * 3.5); particleCount = Mth.m_14045_((int)particleCount, (int)10, (int)70); BlockPos playerPos = player.m_20183_(); BlockState ceilingState = Blocks.f_50069_.m_49966_(); for (i = 3; i < 10; ++i) { BlockState state = level.m_8055_(playerPos.m_6630_(i)); if (state.m_60795_()) continue; ceilingState = state; break; } for (i = 0; i < particleCount; ++i) { double x = player.m_20185_() + (random.nextDouble() - 0.5) * 16.0; double z = player.m_20189_() + (random.nextDouble() - 0.5) * 16.0; double y = player.m_20186_() + 4.0 + random.nextDouble() * 6.0; level.m_7106_((ParticleOptions)new BlockParticleOption(ParticleTypes.f_123814_, ceilingState), x, y, z, 0.0, -0.15, 0.0); } } private static void handleCameraShakeTick() { Minecraft mc = Minecraft.m_91087_(); LocalPlayer player = mc.f_91074_; if (player == null) { if (shakeDurationTicks > 0 || lastYawOffset != 0.0f || lastPitchOffset != 0.0f) { lastYawOffset = 0.0f; lastPitchOffset = 0.0f; shakeDurationTicks = 0; currentShakeIntensity = 0.0f; currentPushIntensity = 0.0f; } return; } player.m_19884_((double)(-lastYawOffset), (double)(-lastPitchOffset)); lastYawOffset = 0.0f; lastPitchOffset = 0.0f; if (shakeDurationTicks > 0) { float progress = (float)shakeDurationTicks / 30.0f; float cameraIntensity = currentShakeIntensity * Mth.m_14031_((float)(progress * (float)Math.PI)); float yawChange = (random.nextFloat() - 0.5f) * 2.0f * cameraIntensity; float pitchChange = (random.nextFloat() - 0.5f) * 1.0f * cameraIntensity; player.m_19884_((double)yawChange, (double)pitchChange); lastYawOffset = yawChange; lastPitchOffset = pitchChange; if (currentPushIntensity > 0.0f) { float pushFactor = currentPushIntensity * Mth.m_14031_((float)(progress * (float)Math.PI)) * 0.1f; player.m_5997_((random.nextDouble() - 0.5) * (double)pushFactor, 0.0, (random.nextDouble() - 0.5) * (double)pushFactor); } --shakeDurationTicks; } else { currentShakeIntensity = 0.0f; currentPushIntensity = 0.0f; } } public static void triggerLineSparks(Vec3 position, float power) { if (!((Boolean)Config.CLIENT.enableLineSparks.get()).booleanValue()) { return; } Minecraft mc = Minecraft.m_91087_(); ClientLevel level = mc.f_91073_; if (level == null) { return; } double amountMultiplier = (Double)Config.CLIENT.lineSparkAmountMultiplier.get(); if (amountMultiplier <= 0.0) { return; } int sparkCount = (int)((double)(power * 15.0f) * amountMultiplier); sparkCount = Mth.m_14045_((int)sparkCount, (int)15, (int)500); for (int i = 0; i < sparkCount; ++i) { Vec3 motion = new Vec3(random.nextDouble() - 0.5, random.nextDouble() - 0.5, random.nextDouble() - 0.5).m_82541_(); float powerFraction = power / 100.0f; float force = random.nextFloat() < 0.25f ? Mth.m_14179_((float)powerFraction, (float)0.5f, (float)8.0f) * (0.9f + random.nextFloat() * 0.4f) : Mth.m_14179_((float)powerFraction, (float)0.3f, (float)4.5f) * (0.7f + random.nextFloat() * 0.4f); motion = motion.m_82490_((double)force); level.m_7106_((ParticleOptions)((SimpleParticleType)ModParticles.LINE_SPARK.get()), position.f_82479_, position.f_82480_, position.f_82481_, motion.f_82479_, motion.f_82480_, motion.f_82481_); } } private static class TrackedSound { final Vec3 explosionPos; final SoundEvent sound; final float volume; final float pitch; long delayTicks; PositionalSoundInstance soundInstance; boolean started = false; private int updateCooldown = 0; private final boolean isPlayerInHouse; TrackedSound(Vec3 explosionPos, SoundEvent sound, float volume, float pitch, long delayTicks, boolean isPlayerInHouse) { this.explosionPos = explosionPos; this.sound = sound; this.volume = volume; this.pitch = pitch; this.delayTicks = delayTicks; this.isPlayerInHouse = isPlayerInHouse; } public void tick(Player player, SoundManager soundManager, RandomSource random) { if (this.soundInstance != null && this.soundInstance.m_7801_()) { return; } if (!this.started) { --this.delayTicks; if (this.delayTicks <= 0L) { Vec3 soundPos = ClientEffects.calculateSoundPosition(player, this.explosionPos, this.isPlayerInHouse); this.soundInstance = new PositionalSoundInstance(this.sound, SoundSource.BLOCKS, this.volume, this.pitch, random, soundPos.f_82479_, soundPos.f_82480_, soundPos.f_82481_); soundManager.m_120367_((SoundInstance)this.soundInstance); this.started = true; } } else { --this.updateCooldown; if (this.updateCooldown <= 0) { this.updateCooldown = 10; Vec3 newSoundPos = ClientEffects.calculateSoundPosition(player, this.explosionPos, this.isPlayerInHouse); this.soundInstance.updatePosition(newSoundPos); } } } public boolean isFinished() { return this.soundInstance != null && this.soundInstance.m_7801_(); } } private static class PendingShake { int delayTicks; final float intensity; final int durationTicks; final float pushIntensity; PendingShake(int delayTicks, float intensity, int durationTicks, float pushIntensity) { this.delayTicks = delayTicks; this.intensity = intensity; this.durationTicks = durationTicks; this.pushIntensity = pushIntensity; } } private static class FlashEffect { final Vec3 explosionPos; final float power; final long startTime; final float maxDurationTicks; final float maxOpacity; final float maxDistance; FlashEffect(Vec3 explosionPos, float power) { this.explosionPos = explosionPos; this.power = power; this.startTime = System.currentTimeMillis(); this.maxDurationTicks = this.calculateDuration(power) * 20.0f; this.maxOpacity = this.calculateMaxOpacity(power); this.maxDistance = this.calculateMaxDistance(power); } private float calculateDuration(float power) { if (power <= 1.0f) { return 0.5f; } if (power <= 5.0f) { return 1.0f; } if (power <= 10.0f) { return 2.5f; } if (power <= 25.0f) { return 3.5f; } return 5.5f; } private float calculateMaxDistance(float power) { if (power <= 1.0f) { return 30.0f; } if (power <= 5.0f) { return 30.0f + (power - 1.0f) * 70.0f / 4.0f; } if (power <= 10.0f) { return 100.0f + (power - 5.0f) * 100.0f / 5.0f; } if (power <= 25.0f) { return 200.0f + (power - 10.0f) * 200.0f / 15.0f; } if (power <= 40.0f) { return 400.0f + (power - 25.0f) * 300.0f / 15.0f; } return 700.0f + (power - 40.0f) * 50.0f; } private float calculateMaxOpacity(float power) { float baseOpacity = power <= 1.0f ? 0.5f : (power <= 5.0f ? 0.7f : (power <= 10.0f ? 0.9f : 1.0f)); return baseOpacity * ((Double)Config.CLIENT.flashMaxOpacity.get()).floatValue(); } public float getCurrentOpacity(Player player) { long elapsed = System.currentTimeMillis() - this.startTime; float elapsedTicks = (float)elapsed / 50.0f; if (elapsedTicks > this.maxDurationTicks) { return 0.0f; } float progress = elapsedTicks / this.maxDurationTicks; float fadeOpacity = this.maxOpacity * (1.0f - progress * progress); double distance = player.m_146892_().m_82554_(this.explosionPos); float distanceFactor = Math.max(0.0f, 1.0f - (float)distance / this.maxDistance); Vec3 viewVec = player.m_20154_(); Vec3 dirToExplosion = this.explosionPos.m_82546_(player.m_146892_()).m_82541_(); float dot = (float)viewVec.m_82526_(dirToExplosion); float angleFactor = Math.max(0.0f, dot); if (!this.isVisible(player, this.explosionPos)) { return 0.0f; } return fadeOpacity * distanceFactor * angleFactor; } private boolean isVisible(Player player, Vec3 explosionPos) { Vec3 start = player.m_146892_(); Vec3 end = explosionPos; ClipContext context = new ClipContext(start, end, ClipContext.Block.VISUAL, ClipContext.Fluid.NONE, (Entity)player); BlockHitResult hit = player.m_9236_().m_45547_(context); if (hit.m_6662_() == HitResult.Type.MISS) { return true; } if (this.power > 10.0f) { int numChecks = Math.max(1, (int)(this.power / 10.0f)); for (int i = 1; i <= numChecks; ++i) { Vec3 elevatedStart = start.m_82520_(0.0, (double)(5 * i), 0.0); Vec3 elevatedEnd = end.m_82520_(0.0, (double)(5 * i), 0.0); ClipContext elevatedContext = new ClipContext(elevatedStart, elevatedEnd, ClipContext.Block.VISUAL, ClipContext.Fluid.NONE, (Entity)player); BlockHitResult elevatedHit = player.m_9236_().m_45547_(elevatedContext); if (elevatedHit.m_6662_() != HitResult.Type.MISS) continue; return true; } } return false; } public boolean isFinished() { long elapsed = System.currentTimeMillis() - this.startTime; return (float)elapsed / 50.0f > this.maxDurationTicks; } } }