Files
Explosion-Overhaul/build/decompiled/com/vinlanx/explosionoverhaul/AmbientExplosionManager.java
2026-05-04 10:03:58 +00:00

377 lines
18 KiB
Java

/*
* 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<UUID, PlayerTimer> playerTimers = new HashMap<UUID, PlayerTimer>();
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<AmbientSoundData> soundsToPlay = new ArrayList<AmbientSoundData>();
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<SoundEvent> 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;
}
}