/* * Decompiled with CFR 0.152. */ package com.vinlanx.explosionoverhaul; import com.vinlanx.explosionoverhaul.CameraShakePacket; import com.vinlanx.explosionoverhaul.Config; import com.vinlanx.explosionoverhaul.DripstoneEffects; import com.vinlanx.explosionoverhaul.ExplosionOverhaul; import com.vinlanx.explosionoverhaul.ModSounds; import com.vinlanx.explosionoverhaul.PacketHandler; import com.vinlanx.explosionoverhaul.PlayTrackedSoundPacket; import com.vinlanx.explosionoverhaul.RedstoneLampEffects; import com.vinlanx.explosionoverhaul.ServerExplosionHandler; import com.vinlanx.explosionoverhaul.SpawnAmbientCaveDustPacket; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; import net.minecraft.core.BlockPos; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundSource; import net.minecraft.util.Mth; import net.minecraft.util.RandomSource; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; import net.minecraftforge.network.PacketDistributor; import net.minecraftforge.registries.ForgeRegistries; public class AmbientExplosionManager { private static final Map playerTimers = new HashMap(); public static void onServerTick(ServerLevel level) { if (!((Boolean)Config.COMMON.ambient.enableAmbientExplosions.get()).booleanValue()) { if (!playerTimers.isEmpty()) { playerTimers.clear(); } return; } for (ServerPlayer player : level.m_6907_()) { PlayerTimer timer = playerTimers.computeIfAbsent(player.m_20148_(), id -> new PlayerTimer(level.m_213780_())); timer.tick(player); } } public static void onPlayerLoggedIn(ServerPlayer player) { playerTimers.put(player.m_20148_(), new PlayerTimer(player.f_8924_.m_129783_().m_213780_())); } public static void onPlayerLoggedOut(ServerPlayer player) { playerTimers.remove(player.m_20148_()); } private static ServerExplosionHandler.CameraShakeProfile determineCameraShakeProfile(float power, double distance, boolean playerInCave, ServerLevel level) { float intensity = 0.0f; int baseDuration = 20; float pushIntensity = 0.0f; int closeDistance = 50; int mediumDistance = 500; int farDistance = 1000; int superFarDistance = 5000; int powerCategory = power <= 3.0f ? 1 : (power <= 6.0f ? 2 : (power <= 14.0f ? 3 : (power <= 30.0f ? 4 : (power <= 60.0f ? 5 : (power <= 99.0f ? 6 : 7))))); int shakeLevel = 0; if (distance <= 50.0) { if (powerCategory >= 7) { shakeLevel = 5; baseDuration = 50; } else if (powerCategory == 6) { shakeLevel = 5; baseDuration = 40; } else if (powerCategory == 5) { shakeLevel = 4; baseDuration = 35; } else if (powerCategory == 4) { shakeLevel = 4; baseDuration = 30; } else if (powerCategory == 3) { shakeLevel = 3; baseDuration = 25; } else if (powerCategory == 2) { shakeLevel = 3; baseDuration = 20; } else if (powerCategory == 1) { shakeLevel = 2; baseDuration = 15; } } else if (distance <= 500.0) { if (powerCategory >= 7) { shakeLevel = 4; baseDuration = 35; } else if (powerCategory == 6) { shakeLevel = 4; baseDuration = 30; } else if (powerCategory == 5) { shakeLevel = 3; baseDuration = 25; } else if (powerCategory == 4) { shakeLevel = 3; baseDuration = 20; } else if (powerCategory <= 3) { shakeLevel = 2; baseDuration = 15; } } else if (distance <= 1000.0) { if (powerCategory >= 7) { shakeLevel = 3; baseDuration = 25; } else if (powerCategory == 6) { shakeLevel = 3; baseDuration = 20; } else if (powerCategory == 5) { shakeLevel = 2; baseDuration = 15; } else if (powerCategory == 4) { shakeLevel = 2; baseDuration = 10; } } else if (distance <= 5000.0) { if (powerCategory >= 7) { shakeLevel = 3; baseDuration = 20; } else if (powerCategory == 6) { shakeLevel = 2; baseDuration = 15; } else if (powerCategory == 5) { shakeLevel = 1; baseDuration = 10; } } switch (shakeLevel) { case 1: { intensity = 0.06f; break; } case 2: { intensity = 0.18f; break; } case 3: { intensity = 0.4f; break; } case 4: { intensity = 0.65f; break; } case 5: { intensity = 0.9f; break; } default: { intensity = 0.0f; baseDuration = 0; } } if (playerInCave && intensity > 0.0f && shakeLevel >= 2) { float basePush = 0.02f + (float)shakeLevel * 0.015f; pushIntensity = Math.min(basePush * (power / 8.0f), 0.25f); pushIntensity = Math.max(0.04f, pushIntensity); } if (intensity > 0.01f && baseDuration < 5) { baseDuration = 5; } if (intensity < 0.01f) { intensity = 0.0f; baseDuration = 0; pushIntensity = 0.0f; } return new ServerExplosionHandler.CameraShakeProfile(intensity, baseDuration, pushIntensity); } private static class PlayerTimer { private final RandomSource random; private int timeUntilNextEvent; PlayerTimer(RandomSource random) { this.random = random; this.resetTimer(); } private void resetTimer() { int max; int min = (Integer)Config.COMMON.ambient.minTimeBetweenExplosions.get(); this.timeUntilNextEvent = min >= (max = ((Integer)Config.COMMON.ambient.maxTimeBetweenExplosions.get()).intValue()) ? min : this.random.m_216339_(min, max); } public void tick(ServerPlayer player) { if (this.timeUntilNextEvent-- <= 0) { this.generateAndPlayAmbientEventForPlayer(player); this.resetTimer(); } } private void generateAndPlayAmbientEventForPlayer(ServerPlayer player) { int shellingWeight; int chainWeight; Config.Common.Ambient.Scenarios scenarios = Config.COMMON.ambient.scenarios; int singleWeight = (Integer)scenarios.singleExplosionWeight.get(); int totalWeight = singleWeight + (chainWeight = ((Integer)scenarios.chainReactionWeight.get()).intValue()) + (shellingWeight = ((Integer)scenarios.shellingWeight.get()).intValue()); if (totalWeight <= 0) { return; } int roll = this.random.m_188503_(totalWeight); AmbientEventType eventType = (roll -= singleWeight) < 0 ? AmbientEventType.SINGLE : ((roll -= chainWeight) < 0 ? AmbientEventType.CHAIN_REACTION : AmbientEventType.SHELLING); Vec3 eventPos = this.generateEventPosition(player); SoundEnvironment chosenEnv = this.determineSoundEnvironment(player, eventPos); if (chosenEnv == null) { return; } boolean playerInHouse = ServerExplosionHandler.isInHouse(player.m_284548_(), player.m_20183_(), player.m_146892_().f_82480_); BlockPos dripstoneCenter = player.m_20183_(); int explosionPower = (int)Math.ceil(this.generatePower()); DripstoneEffects.handleDripstoneFall(player.m_284548_(), dripstoneCenter, explosionPower, player.m_217043_()); ArrayList soundsToPlay = new ArrayList(); switch (eventType) { case SINGLE: { float power = this.generatePower(); if (!(power > 0.0f)) break; soundsToPlay.add(new AmbientSoundData(power, 0L, false)); break; } case CHAIN_REACTION: { int minShots = (Integer)scenarios.minChainReactionShots.get(); int maxShots = (Integer)scenarios.maxChainReactionShots.get(); int shotCount = minShots >= maxShots ? minShots : this.random.m_216339_(minShots, maxShots + 1); long cumulativeDelay = 0L; for (int i = 0; i < shotCount; ++i) { float progress = shotCount > 1 ? (float)i / (float)(shotCount - 1) : 1.0f; float power = Mth.m_14179_((float)(progress * progress), (float)1.0f, (float)40.0f) + this.random.m_188501_() * 4.0f; int minDelay = (Integer)scenarios.minTimeBetweenChainShots.get(); int maxDelay = (Integer)scenarios.maxTimeBetweenChainShots.get(); soundsToPlay.add(new AmbientSoundData(power, cumulativeDelay += minDelay >= maxDelay ? (long)minDelay : (long)this.random.m_216339_(minDelay, maxDelay + 1), false)); } break; } case SHELLING: { float shotPower = 1.0f + this.random.m_188501_() * 3.0f; float impactPower = 5.0f + this.random.m_188501_() * 10.0f; int minDelay = (Integer)scenarios.minShellingDelay.get(); int maxDelay = (Integer)scenarios.maxShellingDelay.get(); long impactDelay = minDelay >= maxDelay ? (long)minDelay : (long)this.random.m_216339_(minDelay, maxDelay + 1); soundsToPlay.add(new AmbientSoundData(shotPower, 0L, true)); soundsToPlay.add(new AmbientSoundData(impactPower, impactDelay, false)); break; } } for (AmbientSoundData soundData : soundsToPlay) { this.playSoundForEnvironment(player, player.m_284548_(), soundData.power(), chosenEnv, playerInHouse, soundData.delay(), soundData.isShellingShot(), eventPos); } } private Vec3 generateEventPosition(ServerPlayer player) { int maxDst; int minDst = (Integer)Config.COMMON.ambient.minExplosionDistance.get(); double distance = minDst >= (maxDst = ((Integer)Config.COMMON.ambient.maxExplosionDistance.get()).intValue()) ? (double)minDst : (double)minDst + this.random.m_188500_() * (double)(maxDst - minDst); double angle = this.random.m_188500_() * 2.0 * Math.PI; double x = player.m_20185_() + Math.cos(angle) * distance; double z = player.m_20189_() + Math.sin(angle) * distance; double y = player.m_20186_(); return new Vec3(x, y, z); } private float generatePower() { Config.Common.Ambient.PowerTiers weights = Config.COMMON.ambient.powerTiers; int totalWeight = (Integer)weights.tier1_weight.get() + (Integer)weights.tier2_weight.get() + (Integer)weights.tier3_weight.get() + (Integer)weights.tier4_weight.get() + (Integer)weights.tier5_weight.get(); if (totalWeight <= 0) { return 0.0f; } int roll = this.random.m_188503_(totalWeight); if ((roll -= ((Integer)weights.tier1_weight.get()).intValue()) < 0) { return 1.0f + this.random.m_188501_() * 3.0f; } if ((roll -= ((Integer)weights.tier2_weight.get()).intValue()) < 0) { return 5.0f + this.random.m_188501_() * 10.0f; } if ((roll -= ((Integer)weights.tier3_weight.get()).intValue()) < 0) { return 16.0f + this.random.m_188501_() * 24.0f; } if ((roll -= ((Integer)weights.tier4_weight.get()).intValue()) < 0) { return 41.0f + this.random.m_188501_() * 39.0f; } if ((roll -= ((Integer)weights.tier5_weight.get()).intValue()) < 0) { return 81.0f + this.random.m_188501_() * (((Double)Config.COMMON.ambient.maxAmbientExplosionPower.get()).floatValue() - 81.0f); } return 0.0f; } private SoundEnvironment determineSoundEnvironment(ServerPlayer player, Vec3 eventPos) { boolean isPlayerInCave = ServerExplosionHandler.isInNaturalCave(player.m_284548_(), player.m_20183_()); Config.Common.Ambient.SoundTypes soundTypes = Config.COMMON.ambient.soundTypes; if (isPlayerInCave) { return (Boolean)soundTypes.enableCaveSounds.get() != false ? SoundEnvironment.CAVE : null; } return (Boolean)soundTypes.enableSurfaceSounds.get() != false ? SoundEnvironment.SURFACE : null; } private void playSoundForEnvironment(ServerPlayer player, ServerLevel level, float power, SoundEnvironment env, boolean playerInHouse, long baseDelay, boolean isShellingShot, Vec3 eventPos) { boolean useAmbientSound; boolean explosionIsInCaveLocation; double explosionY; double distance = player.m_20182_().m_82554_(eventPos); boolean playerInCave = false; switch (env) { case CAVE: { explosionY = player.m_20186_() + (this.random.m_188500_() - 0.5) * 20.0; explosionIsInCaveLocation = true; playerInCave = true; if (isShellingShot || !((Boolean)Config.COMMON.ambient.soundTypes.enableAmbientCaveDust.get()).booleanValue()) break; PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), (Object)new SpawnAmbientCaveDustPacket(power)); if (this.random.m_188500_() < 0.3 + (double)power * 0.02) { ExplosionOverhaul.addDelayedSound(player, (SoundEvent)ModSounds.DUST_SOUND.get(), SoundSource.AMBIENT, (float)player.m_20185_(), (float)player.m_20186_(), (float)player.m_20189_(), 0.7f, 1.0f, player.m_217043_().m_188505_(), baseDelay + (long)this.random.m_188503_(40)); } if (!(this.random.m_188500_() < 0.05 + (double)power * 0.005) || !(power > 15.0f)) break; ExplosionOverhaul.addDelayedSound(player, (SoundEvent)ModSounds.FALLING_STONES_SOUND.get(), SoundSource.AMBIENT, (float)player.m_20185_(), (float)player.m_20186_(), (float)player.m_20189_(), 0.9f, 1.0f, player.m_217043_().m_188505_(), baseDelay + (long)this.random.m_188503_(50)); break; } default: { explosionY = eventPos.m_7098_(); explosionIsInCaveLocation = false; } } Vec3 finalExplosionPos = new Vec3(eventPos.m_7096_(), explosionY, eventPos.m_7094_()); List soundPool = ServerExplosionHandler.getSoundPool((Level)level, power, distance, playerInHouse, explosionIsInCaveLocation); if (soundPool == null || soundPool.isEmpty()) { return; } SoundEvent sound = soundPool.get(this.random.m_188503_(soundPool.size())); ResourceLocation soundId = ForgeRegistries.SOUND_EVENTS.getKey((Object)sound); if (soundId == null) { return; } float volume = Math.min(power * 10.0f, 90.0f); float pitch = 0.95f + this.random.m_188501_() * 0.1f; double speedOfSound = 17.15; long delayTicksEffect = baseDelay + (long)(distance / speedOfSound); if (!isShellingShot) { float lampFlickerPowerThreshold; ServerExplosionHandler.CameraShakeProfile shakeProfile = AmbientExplosionManager.determineCameraShakeProfile(power, distance, playerInCave, level); if (shakeProfile.intensity() > 0.0f && shakeProfile.durationTicks() > 0) { int delayTicks = (int)Math.max(0L, Math.round(distance / speedOfSound)); PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), (Object)new CameraShakePacket(shakeProfile.intensity(), shakeProfile.durationTicks(), shakeProfile.pushIntensity(), delayTicks)); } if (power >= (lampFlickerPowerThreshold = distance > 1000.0 ? 31.0f : (distance > 500.0 ? 20.0f : (distance > 50.0 ? 10.0f : 4.0f)))) { RedstoneLampEffects.triggerLampFlicker(level, player, power, delayTicksEffect, distance); } } boolean bl = useAmbientSound = env == SoundEnvironment.CAVE; if (useAmbientSound) { ExplosionOverhaul.addDelayedSound(player, sound, SoundSource.AMBIENT, (float)player.m_20185_(), (float)player.m_20186_(), (float)player.m_20189_(), volume, pitch, player.m_217043_().m_188505_(), delayTicksEffect); } else { PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), (Object)new PlayTrackedSoundPacket(finalExplosionPos, soundId, volume, pitch, delayTicksEffect, playerInHouse)); } } } private record AmbientSoundData(float power, long delay, boolean isShellingShot) { } private static enum AmbientEventType { SINGLE, CHAIN_REACTION, SHELLING; } private static enum SoundEnvironment { SURFACE, CAVE; } }